Interprocess Communications

The Microsoft® Win32® API provides mechanisms for facilitating communications and data sharing between applications. Collectively, the activities enabled by these mechanisms are called interprocess communications (IPC). Some forms of IPC facilitate the division of labor among several specialized processes. Other forms of IPC facilitate the division of labor among computers on a network.

Typically, applications can use IPC categorized as clients or servers. A client is an application or a process that requests a service from some other application or 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.

  • About Interprocess Communications
  • Choosing an IPC Mechanism
  • Interprocess Communications Reference
Microsoft Platform SDK, February 2001 Edition.
This content last built on Wednesday, February 07, 2001.


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 the applications, and the applications become larger. Large applications eventually become unmanageable, both from a development standpoint and from a user-interface standpoint.

One method you can use to manage larger applications is to produce a specialized application that provides a limited number of features, then enable it to communicate and share data with other specialized applications using some form of IPC. It is not necessary for a single application meet all its users' expectations; applications can communicate and cooperate.

The following IPC mechanisms are supported by the Win32 API:

  • Clipboard
  • COM
  • Dynamic Data Exchange (DDE)
  • File Mapping
  • Mailslots
  • Pipes
  • RPC
  • Windows Sockets
  • WM_COPYDATA


Choosing an IPC Mechanism

After you decide that your application would benefit from IPC, you must decide which of the available IPC methods to use. It is likely that an application will use several IPC mechanisms. For example, all Win32-based applications should provide at least minimal support for the clipboard. In addition, COM and DDE offer the application an opportunity to communicate with applications that support these protocols. By supporting the protocols for the clipboard, COM, and DDE, you enable your application to share data with other applications, without knowing anything about the applications themselves.

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.

  • 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?
  • 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®, 16-bit Windows®, UNIX)?
  • 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?
  • Is performance a critical aspect of the application? All IPC mechanisms include some amount of overhead.
  • Should the application be a GUI application or a console application? Some IPC mechanisms require a GUI application.


Using the Clipboard for IPC

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 standard or application-defined formats. Any other application can then retrieve the data from the clipboard, choosing from the available formats that it understands. The clipboard is a very loosely coupled exchange medium, where applications need only agree on the data format. The applications can reside on the same computer or on different computers on a network.

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.


Using COM for IPC

Applications that use OLE 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, a word processor that uses OLE 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. OLE takes 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. The spreadsheet appears to be an extension of the word processor.

The foundation of OLE is the Component Object Model (COM). A software component that uses COM can communicate with a wide variety of other components, even those that have not yet been written. The components interact as objects and clients. Distributed COM extends the COM programming model so that it works across a network.

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 application that uses OLE. COM objects provide access to an object's data through one or more sets of related functions, known as interfaces. For more information, see COM and ActiveX Object Services.


Using DDE for IPC

DDE is a protocol 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 by the clipboard. 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. You can also define custom DDE data formats for special-purpose IPC between applications with more tightly coupled communications requirements.

DDE exchanges can occur between applications running on the same computer or on different computers on a network.

Key Point DDE is not as efficient as newer technologies. However, you can still use DDE if other IPC mechanisms are not suitable or if you must interface with an existing application that only supports DDE. For more information, see Dynamic Data Exchange and Dynamic Data Exchange Management Library.


Using a File Mapping for IPC

File mapping enables a process to treat the contents of a file as if they were a block of memory in the process's address space. The process can use simple pointer operations to examine and modify the contents of the file. When two or more processes access the same file mapping, each process receives a pointer to memory in its own address space that it can use to read or modify the contents of the file. The processes must use a synchronization object, such as a semaphore, to prevent data corruption in a multitasking environment.

You can use a special case of file mapping to provide named shared memory 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.

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.

Key Point File mapping is an efficient way for two or more processes on the same computer to share data, but you must provide synchronization between the processes. For more information, see File Mapping and Synchronization.


Using a Mailslot for IPC

Mailslots provide one-way communication. Any process that creates a mailslot is a mailslot server. Other processes, called mailslot clients, send messages to the mailslot server by writing a message to its mailslot. Incoming messages are always appended to the mailslot. The mailslot saves the messages until the mailslot server has read them. A process can be both a mailslot server and a mailslot client, so two-way communication is possible using multiple mailslots.

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 all mailslots on a domain can be no longer than 400 bytes, whereas messages sent to a single mailslot are limited only by the maximum message size specified by the mailslot server when it created the mailslot.

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 Pipes for IPC

The Win32 API provides two types of pipes for two-way communication: anonymous pipes and named pipes. Anonymous (or unnamed) pipes enable related processes to transfer information to each other. Typically, an anonymous pipe is used for redirecting the standard input or output of a child process so that it can exchange data with its parent process. To exchange data in both directions (duplex operation), you must create two anonymous pipes. The parent process writes data to one pipe using its write handle, while the child process reads the data from that pipe using its read handle. Similarly, the child process writes data to the other pipe and the parent process reads from it. Anonymous pipes cannot be used over a network, nor can they be used between unrelated processes.

Named pipes are used to transfer data between processes that are not related processes and between processes on different computers. Typically, a named-pipe server process creates a named pipe with a well-known name or a name that is to be communicated to its clients. A named-pipe client process that knows the name of the pipe can open its other end, subject to access restrictions specified by named-pipe server process. After both the server and client have connected to the pipe, they can exchange data by performing read and write operations on the pipe.

Key Point Anonymous pipes provide an efficient way to redirect standard input or output to child processes on the same computer. Named pipes provide a simple programming interface for transferring data between two processes, whether they reside on the same computer or over a network. For more information, see Pipes.


Using RPC for IPC

The Win32 API provides RPC to enable applications to call functions remotely. Therefore, RPC makes IPC as easy as calling a function. RPC operates between processes on a single computer or on different computers 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 Win32-based applications that use RPC are able to communicate with 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.

RPC clients and servers are tightly coupled but still maintain high performance. The system makes extensive use of RPC to facilitate a client-server relationship between different parts of the operating system.

Key Point RPC is a function-level interface, with support for automatic data conversion and for communications with other operating systems. Using RPC, you can create high-performance, tightly coupled distributed applications. For more information, see Microsoft RPC Components.


Using Windows Sockets for IPC

Windows Sockets is an protocol-independent interface. It takes advantage of the communication capabilities of the underlying protocols. In Windows Sockets 2, a socket handle can optionally be used as a file handle with the standard file I/O functions.

Windows Sockets are based on the sockets first popularized by Berkeley Software Distribution (BSD). An application that uses Windows Sockets can communicate with other socket implementation on other types of systems. However, not all transport service providers support all available options.

Key Point Windows Sockets is a protocol-independent interface capable of supporting current and emerging networking capabilities. For more information, see Overview of Windows Sockets 2.


Using WM_COPYDATA for IPC

The WM_COPYDATA message enables you to send data from one application to another. The receiving application gets the data in a COPYDATASTRUCT structure. When data is being passed between a 16-bit Windows-based application and a Win32-based application, the system translates any pointers.

For example code, see the following Platform SDK samples:

  • SPY. This sample, located in MSTOOLS\SAMPLES\SDKTOOLS\SPY, uses WM_COPYDATA to pass data to another application.
  • INTEROP. This sample, located in SCT\SAMPLES, uses WM_COPYDATA to dispatch calls from a 16-bit Windows-based application to a Win32-based DLL.


Interprocess Communications Reference

The following elements are used for interprocess communication.

  • Interprocess Communications Structures
  • Interprocess Communications Messages


Interprocess Communications Structures

The following structure is used for interprocess communication.

COPYDATASTRUCT


COPYDATASTRUCT

The COPYDATASTRUCT structure contains data to be passed to another application by the WM_COPYDATA message.

typedef struct tagCOPYDATASTRUCT {
    ULONG_PTR dwData;
    DWORD     cbData;
    PVOID     lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;

Members

dwData
Specifies data to be passed to the receiving application.
cbData
Specifies the size, in bytes, of the data pointed to by the lpData member.
lpData
Pointer to data to be passed to the receiving application. This member can be NULL.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Interprocess Communications Overview, Interprocess Communications Structures, WM_COPYDATA


Interprocess Communications Messages

The following message is used for interprocess communication.

WM_COPYDATA


WM_COPYDATA

An application sends the WM_COPYDATA message to pass data to another application.

To send this message, call the SendMessage function with the following parameters (do not call the PostMessage function).

SendMessage(
  (HWND) hWnd,              // handle to destination window
  WM_COPYDATA,              // message to send
  (WPARAM) wParam,          // handle to window (HWND)
  (LPARAM) lParam           // data (PCOPYDATASTRUCT)
);

Parameters

wParam
Handle to the window passing the data.
lParam
Pointer to a COPYDATASTRUCT structure that contains the data to be passed.

Return Values

If the receiving application processes this message, it should return TRUE; otherwise, it should return FALSE.

Remarks

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 lParam parameter is valid only during the processing of the message. The receiving application should not free the memory referenced by lParam. If the receiving application must access the data after SendMessage returns, it must copy the data into a local buffer.

When you send a WM_COPYDATA message, SendMessage allocates a block of memory cbData bytes in size and copies the data from the caller's address space to this block. It then sends the message to the destination window. When the receiving window procedure processes this message, the lParam parameter is a pointer to a COPYDATASTRUCT structure that exists in the address space of the receiving process. The lpData member is a pointer to the copied block of memory, and the address reflects the memory location in the receiving process's address space.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Interprocess Communications Overview, Interprocess Communications Messages, SendMessage, COPYDATASTRUCT


Atoms

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
  • Using Atoms
  • Atom Reference


About Atom Tables

The system provides a number of atom tables. Each atom table serves a different purpose. For example, dynamic data exchange (DDE) applications use the global atom table to share item-name and topic-name strings with other applications. Rather than passing actual strings, a DDE application passes global atoms to its partner application. The partner uses the atoms to obtain the strings from the atom table.

Applications can use local atom tables to store their own item-name associations.

The system uses atom tables that are not directly accessible to applications. However, the application uses these atoms when calling the Win32 application programming interface (API). For example, registered clipboard formats are stored in an internal atom table used by the system. An application adds atoms to this atom table using the RegisterClipboardFormat function. Also, registered classes are stored in an internal atom table used by the system. An application adds atoms to this atom table using the RegisterClass or RegisterClassEx function.


Global Atom Table

The global atom table 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 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.

Atom tables are implemented as hash tables. By default, a local atom table uses 37 buckets for its hash table. However, you can change the number of buckets used by calling the InitAtomTable function. If the application calls InitAtomTable, however, it must do so before calling any other atom-management functions.


Atom Types

Applications can create two types of atoms: string atoms and integer atoms. 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.

Several Win32 functions accept either strings or atoms as parameters. When passing an atom to these functions, an application can use the MAKEINTATOM macro to convert the atom into a form that can be used by the function.

The following sections describe atom types.

  • String Atoms
  • Integer Atoms


String Atoms

When applications pass null-terminated strings to the GlobalAddAtom, AddAtom, GlobalFindAtom, and FindAtom functions, they receive string atoms (16-bit integers) in return. String atoms have the following properties:

  • The values of string atoms are in the range 0xC000 (MAXINTATOM) 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 (MAXINTATOM – 1).
  • 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.


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, see Atoms and Shared Memory Objects. For examples that show how to use atoms, see the following topics:

  • Initiating a Conversation
  • Retrieving an Item from the Server
  • Submitting an Item to the Server
  • Terminating a Data Link


Atom Reference

The following elements are used with atoms.

  • Atom Functions
  • Atom Macros


Atom Functions

The following functions are used with atoms.

Function | Description
AddAtom | Adds a character string to the local atom table.
DeleteAtom | Decrements the reference count of a local string atom.
FindAtom | Searches the local atom table for the specified character string.
GetAtomName | Retrieves a copy of the character string associated with the specified local atom.
GlobalAddAtom | Adds a character string to the global atom table.
GlobalDeleteAtom | Decrements the reference count of a global string atom.
GlobalFindAtom | Searches the global atom table for the specified character string.
GlobalGetAtomName | Retrieves a copy of the character string associated with the specified global atom.
InitAtomTable | Initializes the local atom table.


AddAtom

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   // string to add
);

Parameters

lpString
[in] Pointer 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.

Alternatively, you can use an integer atom that has been converted using the MAKEINTATOM macro. See the Remarks for more information.

Return Values

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.

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 is greater than or equal to 0xC000, the return value is zero, indicating an error. If lpString was created by the MAKEINTATOM macro, the low-order word must be in the range 0x0001 through 0xBFFF. If the low-order word is not in this range, the function fails.

If lpString has any other form, AddAtom returns a string atom.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Atoms Overview, Atom Functions, DeleteAtom, FindAtom, GetAtomName, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, GlobalGetAtomName, MAKEINTATOM


DeleteAtom

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
[in] Identifies the atom to be deleted.

Return Values

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 the atom table. The AddAtom function increments the count on each call. The DeleteAtom function decrements the count on each call but removes the string only if the atom's reference count is zero.

Each call to AddAtom should have a corresponding call to DeleteAtom. Do not call DeleteAtom more times than you call AddAtom, or you may delete the atom while other clients are using it.

The DeleteAtom function has no effect on an integer atom (an atom whose value is in the range 0x0001 to 0xBFFF). The function always returns zero for an integer atom.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Atoms Overview, Atom Functions, AddAtom, FindAtom, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, MAKEINTATOM


FindAtom

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   // string to find
);

Parameters

lpString
[in] Pointer to the null-terminated character string to search for.

Alternatively, you can use an integer atom that has been converted using the MAKEINTATOM macro. See the Remarks for more information.

Return Values

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 the system preserves the case of a string in an atom table, the search performed by the FindAtom function is not case sensitive.

If lpString was created by the MAKEINTATOM macro, the low-order word must be in the range 0x0001 through 0xBFFF. If the low-order word is not in this range, the function fails.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Atoms Overview, Atom Functions, AddAtom, DeleteAtom, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom


GetAtomName

The GetAtomName function retrieves a copy of the character string associated with the specified local atom.

UINT GetAtomName(
  ATOM nAtom,       // atom identifying character string
  LPTSTR lpBuffer,  // buffer for atom string
  int nSize         // size of buffer
);

Parameters

nAtom
[in] Specifies the local atom that identifies the character string to be retrieved.
lpBuffer
[out] Pointer to the buffer for the character string.
nSize
[in] Specifies the size, in TCHARs, of the buffer. For ANSI versions of the function this is the number of bytes, while for wide-character (Unicode) versions this is the number of characters.

Return Values

If the function succeeds, the return value is the length of the string copied to the buffer, in TCHARs, 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 whose value is in the range 0x0001 to 0xBFFF) is a null-terminated string in which the first character is a pound sign (#) and the remaining characters represent the unsigned integer atom value.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Atoms Overview, Atom Functions, AddAtom, DeleteAtom, FindAtom, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, GlobalGetAtomName, MAKEINTATOM


GlobalAddAtom

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   // string to add
);

Parameters

lpString
[in] Pointer 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.

Alternatively, you can use an integer atom that has been converted using the MAKEINTATOM macro. See the Remarks for more information.

Return Values

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.

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 is greater than or equal to 0xC000, the return value is zero, indicating an error. If lpString was created by the MAKEINTATOM macro, the low-order word must be in the range 0x0001 through 0xBFFF. If the low-order word is not in this range, the function fails.

If lpString has any other form, GlobalAddAtom returns a string atom.

For an example, see Initiating a Conversation.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Atoms Overview, Atom Functions, AddAtom, DeleteAtom, FindAtom, GetAtomName, GlobalDeleteAtom, GlobalFindAtom, GlobalGetAtomName, MAKEINTATOM


GlobalDeleteAtom

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
[in] Identifies the atom and character string to be deleted.

Return Values

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 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.

Each call to GlobalAddAtom should have a corresponding call to GlobalDeleteAtom. Do not call GlobalDeleteAtom more times than you call GlobalAddAtom, or you may delete the atom while other clients are using it. Applications using DDE should follow the rules on global atom management to prevent leaks and premature deletion.

GlobalDeleteAtom has no effect on an integer atom (an atom whose value is in the range 0x0001 to 0xBFFF). The function always returns zero for an integer atom.

For an example, see Initiating a Conversation.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Atoms Overview, Atom Functions, AddAtom, DeleteAtom, FindAtom, GlobalAddAtom, GlobalFindAtom, MAKEINTATOM


GlobalFindAtom

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   // string to find
);

Parameters

lpString
[in] Pointer to the null-terminated character string for which to search.

Alternatively, you can use an integer atom that has been converted using the MAKEINTATOM macro. See the Remarks for more information.

Return Values

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 the system preserves the case of a string in an atom table as it was originally entered, the search performed by GlobalFindAtom is not case sensitive.

If lpString was created by the MAKEINTATOM macro, the low-order word must be in the range 0x0001 through 0xBFFF. If the low-order word is not in this range, the function fails.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Atoms Overview, Atom Functions, AddAtom, DeleteAtom, FindAtom, GetAtomName, GlobalAddAtom, GlobalDeleteAtom, GlobalGetAtomName


GlobalGetAtomName

The GlobalGetAtomName function retrieves a copy of the character string associated with the specified global atom.

UINT GlobalGetAtomName(
  ATOM nAtom,       // atom identifier
  LPTSTR lpBuffer,  // buffer for atom string
  int nSize         // size of buffer
);

Parameters

nAtom
[in] Identifies the global atom associated with the character string to be retrieved.
lpBuffer
[out] Pointer to the buffer for the character string.
nSize
[in] Specifies the size, in TCHARs, of the buffer. For ANSI versions of the function this is the number of bytes, while for wide-character (Unicode) versions this is the number of characters.

Return Values

If the function succeeds, the return value is the length of the string copied to the buffer, in TCHARs, 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 whose value is in the range 0x0001 to 0xBFFF) is a null-terminated string in which the first character is a pound sign (#) and the remaining characters represent the unsigned integer atom value.

For an example, see Submitting an Item to the Server.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Atoms Overview, Atom Functions, AddAtom, DeleteAtom, FindAtom, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, MAKEINTATOM


InitAtomTable

The InitAtomTable function initializes the local atom table and sets the number of hash buckets to the specified size.

BOOL InitAtomTable(
  DWORD nSize   // size of atom table
);

Parameters

nSize
[in] Specifies the number of hash buckets to use for the atom table. If this parameter is zero, the default number of hash buckets are created.

To achieve better performance, specify a prime number in nSize.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Remarks

An application need not use this function to use a local atom table. The default number of hash buckets used is 37. 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 number of buckets in the global atom table cannot be changed. If the atom table has already been initialized, either explicitly by a prior call to InitAtomTable, or implicitly by the use of any atom-management function, InitAtomTable returns success without changing the number of hash buckets.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Atoms Overview, Atom Functions, AddAtom, DeleteAtom, FindAtom, GetAtomName, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, GlobalGetAtomName


Atom Macros

The following macro is used with atoms.

MAKEINTATOM


MAKEINTATOM

The MAKEINTATOM macro converts the specified atom into a string, so it can be passed to functions which accept either atoms or strings.

LPTSTR MAKEINTATOM(
  WORD wInteger  // integer to make into atom
);

Parameters

wInteger
Specifies the numeric value to be made into an integer atom. This parameter can be either an integer atom or a string atom.

Return Values

The return value is an integer atom cast to a string pointer.

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.

See Also

Atoms Overview, Atom Macros, AddAtom, DeleteAtom, GetAtomName, GlobalAddAtom, GlobalDeleteAtom, GlobalGetAtomName


Clipboard

The clipboard is a set of functions and messages that enable applications to transfer data. Because all applications have access to the clipboard, data can be easily transferred between applications or within an application.

  • About the Clipboard
  • Using the Clipboard
  • Clipboard Reference

This overview does not describe how to copy and paste linked or embedded objects. For information on these subjects, see the COM documentation.


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 in Winuser.h; 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. The following topics describe the clipboard formats.

  • Standard Clipboard Formats
  • Registered Clipboard Formats
  • Private Clipboard Formats
  • Multiple Clipboard Formats
  • Synthesized Clipboard Formats


Standard Clipboard Formats

The clipboard formats defined by the system are called standard clipboard formats. These clipboard formats are described in the following table.

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_DIBV5 | Windows 2000 or later: A memory object containing a BITMAPV5HEADER structure followed by the bitmap color space information and the bitmap bits.
CF_DIF | Software Arts' Data Interchange Format.
CF_DSPBITMAP | Bitmap display format associated with a private format. The hMem parameter must be a handle to 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 hMem parameter must be a handle to 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 hMem parameter must be a handle to 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 hMem parameter must be a handle to data that can be displayed in text format in lieu of the privately formatted data.
CF_ENHMETAFILE | A handle to an enhanced metafile (HENHMETAFILE).
CF_GDIOBJFIRST through CF_GDIOBJLAST | 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 hMem parameter is not a handle to a GDI object, but is a handle allocated by the GlobalAlloc function with the GMEM_MOVEABLE flag.
CF_HDROP | A handle to 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 The data is a handle to the locale identifier associated with text in the clipboard. When you close the clipboard, if it contains CF_TEXT data but no CF_LOCALE data, the system automatically sets the CF_LOCALE format to the current input language. 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 formatted text data type such as RTF instead.

Windows NT/2000 or later: The system uses the code page associated with CF_LOCALE to implicitly convert from CF_TEXT to CF_UNICODETEXT. Therefore, the correct code page table is used for the conversion.
CF_METAFILEPICT | Handle to 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 hMem 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 hMem parameter must be NULL.
CF_PALETTE | Handle to 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, the 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/2000 or later: Unicode text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data.


Registered Clipboard Formats

Many applications work with data that cannot be translated into a standard clipboard format without loss of information. These applications can create their own clipboard formats. A clipboard format that is defined by an application, 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).

To register a new clipboard format, use the RegisterClipboardFormat function. This function takes the name of the format and returns and unsigned integer value that represents the registered clipboard format. To retrieve the name of the registered clipboard format, pass the unsigned integer value to the GetClipboardFormatName function.

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.


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_MOVEABLE flag. 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. To find out how many formats are currently used on the clipboard, call the CountClipboardFormats function.

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 as indicated in the following table.

Clipboard Format | Conversion Format | Platform Support
CF_BITMAP | CF_DIB | Windows NT/2000, Windows 95/98
CF_BITMAP | CF_DIBV5 | Windows 2000
CF_DIB | CF_BITMAP | Windows NT/2000, Windows 95/98
CF_DIB | CF_PALETTE | Windows NT/2000, Windows 95/98
CF_DIB | CF_DIBV5 | Windows 2000
CF_DIBV5 | CF_BITMAP | Windows 2000
CF_DIBV5 | CF_DIB | Windows 2000
CF_DIBV5 | CF_PALETTE | Windows 2000
CF_ENHMETAFILE | CF_METAFILEPICT | Windows NT/2000, Windows 95/98
CF_METAFILEPICT | CF_ENHMETAFILE | Windows NT/2000, Windows 95/ 98
CF_OEMTEXT | CF_TEXT | Windows NT/2000, Windows 95/98
CF_OEMTEXT | CF_UNICODETEXT | Windows NT/2000
CF_TEXT | CF_OEMTEXT | Windows NT/2000, Windows 95/98
CF_TEXT | CF_UNICODETEXT | Windows NT/2000
CF_UNICODETEXT | CF_OEMTEXT | Windows NT/2000
CF_UNICODETEXT | CF_TEXT | Windows NT/2000

If the 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 system first enumerates the format that is on the clipboard, followed by the formats to which it can be converted.

When copying bitmaps, it is best to place the CF_DIB or CF_DIBV5 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 the CF_DIB or CF_DIBV5 format is on the clipboard and a window requests the CF_BITMAP format, the system renders the device-independent 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 or CF_DIBV5 clipboard format as soon as the clipboard is closed. This ensures that the correct palette is used to generate the DIB. If you place the CF_DIBV5 format with the bitmap color space information in the clipboard, the system will convert the bitmap bits from the bitmap color space to the sRGB color space when CF_DIB or CF_DIBV5 is requested. If CF_DIBV5 is requested when there is no color space information in the clipboard, the system returns sRGB color space information in the BITMAPV5HEADER structure. Conversions between other clipboard formats occur upon demand.

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.

There are two clipboard formats for metafiles: CF_ENHMETAFILE and CF_METAFILEPICT. Specify CF_ENHMETAFILE for enhanced metafiles and CF_METAFILEPICT for Windows metafiles.


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. To find out which window has the clipboard open, call the GetOpenClipboardWindow function. 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. To find out which window owns the clipboard, call the GetClipboardOwner function.

After emptying the clipboard, the window places data on the clipboard in as many clipboard formats as possible, ordered from the most descriptive clipboard format to the least descriptive. 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, see Delayed Rendering.


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 to 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_MOVEABLE flag.

After 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 specified function:

Function 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_DIBV5 CF_DSPTEXT CF_OEMTEXT CF_TEXT CF_UNICODETEXT
None | CF_OWNERDISPLAY

When the clipboard is emptied of a CF_OWNERDISPLAY object, 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 to the next window in the chain. To retrieve the handle to the first window in the chain, call the GetClipboardViewer function.

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.


Clipboard Sequence Number

The clipboard for each window station has an associated clipboard sequence number. This number is incremented whenever the contents of the clipboard change. To obtain the clipboard sequence number, call the GetClipboardSequenceNumber function.


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 accelerators, 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 WINAPI 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, 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 WINAPI 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_MOVEABLE,
            (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 to 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 WINAPI 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 WINAPI 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_MOVEABLE,
            (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_MOVEABLE, 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)
    {
        //
        // Handle other messages.
        //

        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 to 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 Message

Platform SDK: Interprocess Communications

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_MOVEABLE,
                        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_MOVEABLE, 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 WINAPI 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 WINAPI 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 WINAPI 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 elements are associated with using the clipboard.

  • Clipboard Functions
  • Clipboard Structures
  • Clipboard Messages


Clipboard Functions

The following functions are used with the clipboard.

Function | Description
ChangeClipboardChain | Removes a specified window from the chain of clipboard viewers.
CloseClipboard | Closes the clipboard.
CountClipboardFormats | Retrieves the number of different data formats currently on the clipboard.
EmptyClipboard | Empties the clipboard and frees handles to data in the clipboard.
EnumClipboardFormats | Enumerates the data formats currently available on the clipboard.
GetClipboardData | Retrieves data from the clipboard in a specified format.
GetClipboardFormatName | Retrieves from the clipboard the name of the specified registered format.
GetClipboardOwner | Retrieves the window handle of the current owner of the clipboard.
GetClipboardSequenceNumber | Retrieves the clipboard sequence number for the current window station.
GetClipboardViewer | Retrieves the handle to the first window in the clipboard viewer chain.
GetOpenClipboardWindow | Retrieves the handle to the window that currently has the clipboard open.
GetPriorityClipboardFormat | Retrieves the first available clipboard format in the specified list.
IsClipboardFormatAvailable | Determines whether the clipboard contains data in the specified format.
OpenClipboard | Opens the clipboard for examination and prevents other applications from modifying the clipboard content.
RegisterClipboardFormat | Registers a new clipboard format.
SetClipboardData | Places data on the clipboard in a specified clipboard format.
SetClipboardViewer | Adds the specified window to the chain of clipboard viewers.


ChangeClipboardChain

The ChangeClipboardChain function removes a specified window from the chain of clipboard viewers.

BOOL ChangeClipboardChain(
  HWND hWndRemove,  // handle to window to remove
  HWND hWndNewNext  // handle to next window
);

Parameters

hWndRemove
[in] Handle to the window to be removed from the chain. The handle must have been passed to the SetClipboardViewer function.
hWndNewNext
[in] Handle to 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 Values

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.

For an example, see Removing a Window from the Clipboard Viewer Chain.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, ChangeClipboardChain, SetClipboardViewer, WM_CHANGECBCHAIN


CloseClipboard

The CloseClipboard function closes the clipboard.

BOOL CloseClipboard(VOID);

Parameters

This function has no parameters.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

For an example, see Example of a Clipboard Viewer.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, GetOpenClipboardWindow, OpenClipboard


CountClipboardFormats

The CountClipboardFormats function retrieves the number of different data formats currently on the clipboard.

int CountClipboardFormats(VOID);

Parameters

This function has no parameters.

Return Values

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.

For an example, see Example of a Clipboard Viewer.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, EnumClipboardFormats, RegisterClipboardFormat


EmptyClipboard

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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

For an example, see Copying Information to the Clipboard.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, OpenClipboard, SetClipboardData, WM_DESTROYCLIPBOARD


EnumClipboardFormats

The EnumClipboardFormats function enumerates the data formats 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   // available clipboard format
);

Parameters

format
[in] 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 Values

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 system provides automatic type conversions for certain clipboard formats. In the case of such a format, this function enumerates the specified format, then enumerates the formats to which it can be converted. For more information, see Standard Clipboard Formats and Synthesized Clipboard Formats.

For an example, see Example of a Clipboard Viewer.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, CountClipboardFormats, OpenClipboard, RegisterClipboardFormat


GetClipboardData

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
[in] Specifies a clipboard format. For a description of the standard clipboard formats, see Standard Clipboard Formats.

Return Values

If the function succeeds, the return value is the handle to 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 must not free the handle nor leave it locked. The application must not use the handle after the EmptyClipboard or CloseClipboard function is called, or after the SetClipboardData function is called with the same clipboard format.

The 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. For more information, see Synthesized Clipboard Formats.

For an example, see Pasting Information from the Clipboard.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, CloseClipboard, EmptyClipboard, EnumClipboardFormats, SetClipboardData


GetClipboardFormatName

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,  // format name
  int cchMaxCount         // length of format name buffer
);

Parameters

format
[in] Specifies the type of format to be retrieved. This parameter must not specify any of the predefined clipboard formats.
lpszFormatName
[out] Pointer to the buffer that is to receive the format name.
cchMaxCount
[in] Specifies the maximum length, in TCHARs, of the string to be copied to the buffer. If the name exceeds this limit, it is truncated. For the ANSI version of the function, this is the number of bytes. For the wide-character (Unicode) version, this is the number of characters.

Return Values

If the function succeeds, the return value is the length, in TCHARs, 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.

For an example, see Example of a Clipboard Viewer.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Clipboard Overview, Clipboard Functions, EnumClipboardFormats, RegisterClipboardFormat


GetClipboardOwner

The GetClipboardOwner function retrieves the window handle of the current owner of the clipboard.

HWND GetClipboardOwner(VOID);

Parameters

This function has no parameters.

Return Values

If the function succeeds, the return value is the handle to 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.

For an example, see Example of a Clipboard Viewer.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, EmptyClipboard, GetClipboardViewer


GetClipboardSequenceNumber

The GetClipboardSequenceNumber function retrieves the clipboard sequence number for the current window station.

DWORD GetClipboardSequenceNumber(VOID);

Parameters

This function has no parameters.

Return Values

The return value is the clipboard sequence number. If you do not have WINSTA_ACCESSCLIPBOARD access to the window station, the function returns zero.

Remarks

The system keeps a serial number for the clipboard for each window station. This number is incremented whenever the contents of the clipboard change or the clipboard is emptied. You can track this value to determine whether the clipboard contents have changed and optimize creating DataObjects. If clipboard rendering is delayed, the sequence number is not incremented until the changes are rendered.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions


GetClipboardViewer

The GetClipboardViewer function retrieves the handle to the first window in the clipboard viewer chain.

HWND GetClipboardViewer(VOID);

Parameters

This function has no parameters.

Return Values

If the function succeeds, the return value is the handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, GetClipboardOwner, SetClipboardViewer


GetOpenClipboardWindow

The GetOpenClipboardWindow function retrieves the handle to the window that currently has the clipboard open.

HWND GetOpenClipboardWindow(VOID);

Parameters

This function has no parameters.

Return Values

If the function succeeds, the return value is the handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, GetClipboardOwner, GetClipboardViewer, OpenClipboard


GetPriorityClipboardFormat

The GetPriorityClipboardFormat function retrieves the first available clipboard format in the specified list.

int GetPriorityClipboardFormat(
  UINT *paFormatPriorityList,  // array of clipboard formats
  int cFormats                 // number of entries in array
);

Parameters

paFormatPriorityList
[in] Pointer to an array of unsigned integers identifying clipboard formats, in priority order. For a description of the standard clipboard formats, see Standard Clipboard Formats.
cFormats
[in] Specifies the number of entries in the paFormatPriorityList array. This value must not be greater than the number of entries in the list.

Return Values

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.

For an example, see Example of a Clipboard Viewer.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, CountClipboardFormats, EnumClipboardFormats, GetClipboardFormatName, IsClipboardFormatAvailable, RegisterClipboardFormat


IsClipboardFormatAvailable

The IsClipboardFormatAvailable function determines whether the clipboard contains data in the specified format.

BOOL IsClipboardFormatAvailable(
  UINT format   // clipboard format
);

Parameters

format
[in] Specifies a standard or registered clipboard format. For a description of the standard clipboard formats, see Standard Clipboard Formats.

Return Values

If the clipboard format is available, the return value is nonzero.

If the clipboard format is not available, the return value is zero. 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.

For an example, see Pasting Information from the Clipboard.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, CountClipboardFormats, EnumClipboardFormats, GetPriorityClipboardFormat, RegisterClipboardFormat, WM_INITMENU, WM_INITMENUPOPUP


OpenClipboard

The OpenClipboard function opens the clipboard for examination and prevents other applications from modifying the clipboard content.

BOOL OpenClipboard(
  HWND hWndNewOwner   // handle to window
);

Parameters

hWndNewOwner
[in] Handle to the window to be associated with the open clipboard. If this parameter is NULL, the open clipboard is associated with the current task.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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 hWndNewOwner parameter does not become the clipboard owner unless the EmptyClipboard function is called.

For an example, see Copying Information to the Clipboard.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, CloseClipboard, EmptyClipboard


RegisterClipboardFormat

The RegisterClipboardFormat function registers a new clipboard format. This format can then be used as a valid clipboard format.

UINT RegisterClipboardFormat(
  LPCTSTR lpszFormat   // name of new format
);

Parameters

lpszFormat
[in] Pointer to a null-terminated string that names the new format.

Return Values

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. Note that the format name comparison is case-insensitive.

Registered clipboard formats are identified by values in the range 0xC000 through 0xFFFF.

When registered clipboard formats are placed on or retrieved from the clipboard, they must be in the form of an HGLOBAL value.

For an example, see Registering a Clipboard Format.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Clipboard Overview, Clipboard Functions, CountClipboardFormats, EnumClipboardFormats, GetClipboardFormatName


SetClipboardData

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 hMem   // data handle
);

Parameters

uFormat
[in] Specifies a clipboard format. This parameter can be a registered format or any of the standard clipboard formats. For more information, see Registered Clipboard Formats and Standard Clipboard Formats.
hMem
[in] Handle to 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.

After SetClipboardData is called, the system owns the object identified by the hMem parameter. The application can read the data, but must not free the handle or leave it locked until the CloseClipboard function is called. (The application can access the data after calling CloseClipboard). If the hMem parameter identifies a memory object, the object must have been allocated using the GlobalAlloc function with the GMEM_MOVEABLE flag.

Return Values

If the function succeeds, the return value is the handle to 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 standard clipboard formats. For more information, see Registered Clipboard Formats and Standard Clipboard Formats.

If an application calls SetClipboardData in response to WM_RENDERFORMAT or WM_RENDERALLFORMATS, the application should not use the handle after SetClipboardData has been called.

The 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. For more information, see Synthesized Clipboard Formats.

For an example, see Copying Information to the Clipboard.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, CloseClipboard, GetClipboardData, OpenClipboard, RegisterClipboardFormat, WM_RENDERFORMAT, WM_RENDERALLFORMATS


SetClipboardViewer

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 hWndNewViewer   // handle to clipboard viewer window
);

Parameters

hWndNewViewer
[in] Handle to the window to be added to the clipboard chain.

Return Values

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.

For an example, see Adding a Window to the Clipboard Viewer Chain.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Clipboard Overview, Clipboard Functions, ChangeClipboardChain, GetClipboardViewer, SendMessage


Clipboard Structures

The following structure is used with the clipboard.

METAFILEPICT


METAFILEPICT

The METAFILEPICT structure defines the metafile picture format used for exchanging metafile data through the clipboard.

typedef struct tagMETAFILEPICT {
    LONG      mm;
    LONG      xExt;
    LONG      yExt;
    HMETAFILE hMF;
} METAFILEPICT, *LPMETAFILEPICT;

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
Handle to a memory metafile.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Wingdi.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Structures, SetClipboardData


Clipboard Messages

Following are the messages used with the clipboard.

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


WM_ASKCBFORMATNAME

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.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_ASKCBFORMATNAME
  WPARAM wParam,   // size of buffer
  LPARAM lParam    // format name (LPTSTR)
);

Parameters

wParam
Specifies the size, in characters, of the buffer pointed to by the lParam parameter.
lParam
Pointer to the buffer that is to receive the clipboard format name.

Return Values

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 wParam 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages


WM_CHANGECBCHAIN

The WM_CHANGECBCHAIN message is sent to the first window in the clipboard viewer chain when a window is being removed from the chain.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_CHANGECBCHAIN
  WPARAM wParam,   // handle to window to be removed (HWND)
  LPARAM lParam    // handle to next window in chain (HWND)
);

Parameters

wParam
Handle to the window being removed from the clipboard viewer chain.
lParam
Handle to 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 Values

If an application processes this message, it should return zero.

Remarks

Each clipboard viewer window saves the handle to 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 the lParam parameter as the next window in the chain.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, SendMessage, SetClipboardViewer


WM_CLEAR

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.

To send this message, call the SendMessage function with the following parameters.

SendMessage(
  (HWND) hWnd,              // handle to destination window
  WM_CLEAR,                 // message to send
  (WPARAM) wParam,          // not used; must be zero
  (LPARAM) lParam          // not used; must be zero
);

Parameters

This message has no parameters.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, EM_UNDO, WM_COPY, WM_CUT, WM_PASTE


WM_COPY

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.

To send this message, call the SendMessage function with the following parameters.

SendMessage(
  (HWND) hWnd,              // handle to destination window
  WM_COPY,                  // message to send
  (WPARAM) wParam,          // not used; must be zero
  (LPARAM) lParam          // not used; must be zero
);

Parameters

This message has no parameters.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, WM_CLEAR, WM_CUT, WM_PASTE


WM_CUT

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.

To send this message, call the SendMessage function with the following parameters.

SendMessage(
  (HWND) hWnd,              // handle to destination window
  WM_CUT,                   // message to send
  (WPARAM) wParam,          // not used; must be zero
  (LPARAM) lParam          // not used; must be zero
);

Parameters

This message has no parameters.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, EM_UNDO, WM_CLEAR, WM_COPY, WM_PASTE


WM_DESTROYCLIPBOARD

The WM_DESTROYCLIPBOARD message is sent to the clipboard owner when a call to the EmptyClipboard function empties the clipboard.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_DESTROYCLIPBOARD
  WPARAM wParam,   // not used
  LPARAM lParam    // not used
);

Parameters

This message has no parameters.

Return Values

If an application processes this message, it should return zero.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, EmptyClipboard


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.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_DRAWCLIPBOARD
  WPARAM wParam,   // not used
  LPARAM lParam    // not used
);

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 to the next window in the chain is returned by SetClipboardViewer, and may change in response to a WM_CHANGECBCHAIN message.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, SendMessage, SetClipboardViewer, WM_CHANGECBCHAIN


WM_HSCROLLCLIPBOARD

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.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // WM_HSCROLLCLIPBOARD
  WPARAM wParam,  // handle to window (HWND)
  LPARAM lParam   // scroll bar code and scroll box position
);

Parameters

wParam
Handle to the clipboard viewer window.
lParam
The low-order word of lParam specifies a scroll bar event. This parameter can be one of the following values.
Value | Meaning
SB_ENDSCROLL | End scroll.
SB_LEFT | Scroll to upper left.
SB_RIGHT | Scroll to lower right.
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 | Scroll to absolute position. The current position is specified by the high-order word.

The high-order word of lParam specifies the current position of the scroll box if the low-order word of lParam is SB_THUMBPOSITION; otherwise, the high-order word is not used.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, HIWORD, LOWORD, ScrollWindow


WM_PAINTCLIPBOARD

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.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_PAINTCLIPBOARD
  WPARAM wParam,   // handle to window (HWND)
  LPARAM lParam    // handle to memory object (HGLOBAL)
);

Parameters

wParam
Handle to the clipboard viewer window.
lParam
Handle to a global memory object that contains a PAINTSTRUCT structure. The structure defines the part of the client area to paint.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, GlobalLock, GlobalUnlock, PAINTSTRUCT, WM_SIZECLIPBOARD


WM_PASTE

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.

To send this message, call the SendMessage function with the following parameters.

SendMessage(
  (HWND) hWnd,              // handle to destination window
  WM_PASTE,                 // message to send
  (WPARAM) wParam,          // not used; must be zero
  (LPARAM) lParam          // not used; must be zero
);

Parameters

This message has no parameters.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, WM_CLEAR, WM_COPY, WM_CUT


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.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_RENDERALLFORMATS
  WPARAM wParam,   // not used
  LPARAM lParam    // not used
);

Parameters

This message has no parameters.

Return Values

If an application processes this message, it should return zero.

Remarks

When responding to a WM_RENDERALLFORMATS message, the clipboard owner must call the OpenClipboard and EmptyClipboard functions 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, EmptyClipboard, OpenClipboard, SetClipboardData, WM_RENDERFORMAT


WM_RENDERFORMAT

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.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_RENDERFORMAT
  WPARAM wParam,   // clipboard format (UINT)
  LPARAM lParam    // not used
);

Parameters

wParam
Specifies the clipboard format to be rendered.
lParam
This parameter is not used.

Return Values

If an application processes this message, it should return zero.

Remarks

When responding to a WM_RENDERFORMAT message, the clipboard owner must not open the clipboard before calling SetClipboardData.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, SetClipboardData, WM_RENDERALLFORMATS


WM_SIZECLIPBOARD

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.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_SIZECLIPBOARD
  WPARAM wParam,   // handle to window (HWND)
  LPARAM lParam    // handle to memory object (HGLOBAL)
);

Parameters

wParam
Handle to the clipboard viewer window.
lParam
Handle to a global memory object that contains a RECT structure. The structure specifies the new dimensions of the clipboard viewer's client area.

Return Values

If an application processes this message, it should return zero.

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, GlobalLock, GlobalUnlock, RECT


WM_VSCROLLCLIPBOARD

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.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // WM_VSCROLLCLIPBOARD
  WPARAM wParam,  // handle to window (HWND)
  LPARAM lParam   // scroll bar code and scroll box position
);

Parameters

wParam
Handle to the clipboard viewer window.
lParam
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 high-order word.
SB_TOP | Scroll to upper left.

The high-order word of lParam specifies the current position of the scroll box if the low-order word of lParam is SB_THUMBPOSITION; otherwise, the high-order word of lParam is not used.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Clipboard Overview, Clipboard Messages, HIWORD, LOWORD, ScrollWindow


HTML Clipboard Format

The requirements for transferring HTML text by means of the clipboard differ depending on scenario. This article is concerned with cutting and pasting fragments of an HTML document. There may be requirements for transferring entire HTML documents through the clipboard; however, this article is driven by a requirement to transfer fragments of selected HTML text. As such, a method that required the entire HTML document to be copied to the clipboard is seen as too heavyweight.

The CF_HTML clipboard format allows a fragment of raw HTML text and its context to be stored on the clipboard as ASCII. This allows the context of the HTML fragment, which consists of all preceding surrounding tags, to be examined by an application so that the surrounding tags of the HTML fragment can be noted with their attributes. Although it is up to applications to decide how to interpret such fragments, some basic guidelines are included here based on IE4/MSHTML implementations.

The official name of the clipboard (the string used by RegisterClipboardFormat) is HTML Format.

Description

Scenarios

Description

CF_HTML is entirely text format (to be, among other things, in the HTML spirit, and uses UTF-8) and includes a description, an optional context, and, within the context, the fragment.

The following is an example of a clipboard:

Version:0.9
    StartHTML:71
    EndHTML:170
    StartFragment:140
    EndFragment:160
    StartSelection:140
    EndSelection:160
    <!DOCTYPE>
    <HTML>
    <HEAD>
    <TITLE> The HTML Clipboard</TITLE>
    <BASE HREF="http://sample/specs">
    </HEAD>
    <BODY>
    <UL>
    <!--StartFragment -->
    <LI> The Fragment </LI>
    <!--EndFragment -->
    </UL>
    </BODY>
    </HTML>

The description includes the clipboard version number and offsets, indicating where the context and the fragment start and end. The description is a list of ASCII text keywords (min/maj is not meaningful) followed by a string and separated by a colon (:).

Version: vv version number of the clipboard. Starting version is 0.9.
StartHTML: bytecount from the beginning of the clipboard to the start of the context, or -1 if no context.
EndHTML: bytecount from the beginning of the clipboard to the end of the context, or -1 if no context.
StartFragment: bytecount from the beginning of the clipboard to the start of the fragment.
EndFragment: bytecount from the beginning of the clipboard to the end of the fragment.
StartSelection: bytecount from the beginning of the clipboard to the start of the selection.
EndSelection: bytecount from the beginning of the clipboard to the end of the selection.

The StartSelection and EndSelection keywords are optional and must both be omitted if you do not want the application to generate this information.

Other information of this kind could be added here later, since the HTML starts at the StartHTMLoffset. For example, multiple pairs of StartFragment / EndFragment could be added later to support noncontiguous selection of fragments.

For the convenience of the programs generating the bytecounts, bytecounts could be left padded by zeros. For example, programs generating the bytecounts could arbitrarily affect ten (10) zeros to each keyword (StartHTML: 0000000000) and then, when the exact StartHTML bytecount is known (say, 71), the program can replace the appropriate number of zeros by the bytecount (StartHTML: 0000000071).

The only character set supported by the clipboard is Unicode in its UTF-8 encoding. Because the first characters of UTF-8 and ASCII match, the description is always ASCII, but the bytes of the context (starting at StartHTML) could be using any other characters coded in UTF-8.

End of lines in the clipboard format header could be CR or CR/LF or LF.

The fragment contains pure, valid HTML representing the area the user has selected (to Copy, for example). This contains the selected text plus the opening tags and attributes of any element that has an end tag within the selected text, and end tags at the end of the fragment for any start tag included. This is all information required for basic pasting of an HTML fragment.

The fragment should be preceded and followed by the HTML comments <!--StartFragment--> and <!--EndFragment--> (no space allowed between the !-- and the text) to conveniently indicate where the fragment starts and ends. Thus the start and end of the fragment are indicated by the presence of these comments and by StartFragment and EndFragment byte counts in the description. Tools are expected to produce this information. This redundancy has been introduced to be able to rapidly find the start of the fragment (from the byte count) and mark the position of the fragment directly in the HTML tree.

The selection indicates inside the fragment the exact HTML area the user has selected (to Copy, for example). This adds more information to the fragment by indicating the exact selected text, without the opening tags and end tags that have been added to ensure the fragment is well-formed HTML.

The selection is optional, as sufficient information is included in the fragment for basic pasting. If the selection is not stored, both StartSelection and EndSelection are not stored in the header.

The context is a valid, complete HTML document. This article contains the fragment and all preceding surrounding tags (start and end tags; these preceding surrounding tags represent all the parent nodes of the fragment, until the HTML node). The article also contains the complete HEAD, and allows the BASE and TITLE elements, for example, to be included so this additional information can be obtained. An application copying a fragment of HTML to the clipboard can choose to create a BASE element to include in the context if such an element is not already present so that partial URLs in the fragment can be resolved.

The context is optional, as sufficient information is included in the fragment for basic pasting of an HTML fragment to take place. If the context is not stored, the fragment only is stored and the StartHTML=EndHTML=-1.

Scenarios

The following scenarios describe how the IE4/MSHTML HTML editor handles HTML cut and paste; other applications may or may not follow these scenarios. The clipboard format described here is intended to allow flexibility for how an application chooses to function. (These scenarios show only good HTML, that is, no overlapping tags.)

  1. Simple Fragment of HTML.
    • HTML text:
      <BODY>This is normal <B>This is bold </B><I><B>This is bold italic </B>This is italic </I></BODY>
    • Appears as:
      This is normal This is bold This is bold italic This is italic
    • The text between the ** is selected and copied to the clipboard:
      This is normal This is **bold This is bold italic This** is italic
    • This is what will be on the clipboard (note this is IE4/MSHTML's interpretation):
      Version:0.9
      StartHTML:71
      EndHTML:160
      StartFragment:130
      EndFragment:150
      StartSelection:130
      EndSelection:150
      <!DOCTYPE ...>
      <HTML>
      <BODY>
      <!--StartFragment-->
      <B>bold </B><I><B>This is bold italic </B>This</I>
      <!--EndFragment-->
      </BODY>
      </HTML>
    • In this scenario only the BODY tag and the HTML tag appear in the context as it precedes the selected fragment. Note that start tags and end tags are included in the context. The selection, as delimited by StartSelection and EndSelection, is shown in bold.
  2. Fragment of a table in HTML.
    • HTML text:
      <BODY><TABLE BORDER><TR><TH ROWSPAN=2>Head1</TH><TD>Item 1</TD> <TD>Item 2</TD> <TD>Item 3</TD> <TD>Item 4</TD></TR><TR><TD>Item 5</TD> <TD>Item 6</TD> <TD>Item 7</TD> <TD>Item 8</TD></TR><TR><TH>Head2</TH><TD>Item 9</TD> <TD>Item 10</TD> <TD>Item 11</TD> <TD>Item 12</TD></TR></TABLE></BODY>
    • Appears as:
      Head1 | Item 1 | Item 2 | Item 3 | Item 4
      Item 5 | Item 6 | Item 7 | Item 8
      Head2 | Item 9 | Item 10 | Item 11 | Item 12

    • The Item 6, Item7, Item 10, and Item 11 elements of the table are selected as a block and copied to the clipboard.
    • This is what will be on the clipboard (note this is IE4/MSHTML's interpretation):
      <!DOCTYPE ...>
      <HTML><BODY><TABLE BORDER>
      <!--StartFragment-->
      <TR><TD>Item 6</TD> <TD>Item 7</TD></TR><TR><TD>Item 10</TD> <TD>Item 11</TD></TR>
      <!--EndFragment-->
      </TABLE>
      </BODY></HTML>
      The selection, as delimited by StartSelection and EndSelection, is shown in bold.
  3. Pasting a fragment of an ordered list into plain text.
    • HTML text:
      <BODY><OL TYPE = a><LI>Item 1<LI>Item 2<LI>Item 3<LI>Item 4<LI>Item 5<LI>Item 6</OL></BODY>
    • Appears as:
      1. Item 1
      2. Item 2
      3. Item 3
      4. Item 4
      5. Item 5
      6. Item 6
    • The user selects and copies items 3 through 5 to the clipboard.
      The following HTML is in the clipboard:
      <DOCTYPE...><HTML><BODY><OL TYPE = a>
      <!-- StartFragment-->
      <LI>Item 3<LI>Item 4<LI>Item 5
      <!-- EndFragment-->
      </OL></BODY></HTML>
      The selection, as delimited by StartSelection and EndSelection, is show in bold.
    • If this fragment is now pasted into an empty document, the following HTML will be created:
      <BODY><OL TYPE = a><LI>Item 3<LI>Item 4<LI>Item 5</OL></BODY>
    • Appearing as:
      1. Item 3
      2. Item 4
      3. Item 5
  4. Pasting a partially selected region.
    • HTML text:
      <P> IE4/MSHTML is a WYSIWYG Editor that supports :<UL><LI>Cut<LI>Copy<LI>Paste
      </UL> <P>This is a Great Tool !
    • Appears as:
      IE4/MSHTML is a WYSIWYG Editor that supports :
      • Cut
      • Copy
      • Paste
    • The user selects from "WYSIWYG" until "Cop".
      The following HTML is in the clipboard:
      <DOCTYPE...><HTML><BODY>
      <!-- StartFragment-->
      <P>
      WYSIWYG Editor, which supports
      <UL><LI>Cut<LI>Cop
      </UL>
      <!-- EndFragment-->
      </BODY></HTML>
      The selection, as delimited by StartSelection and EndSelection, is shown in bold.
    • The user selects from "opy" until "Great".
      The following HTML is in the clipboard:
      <DOCTYPE...><HTML><BODY>
      <!-- StartFragment-->
      <UL><LI>
      opy<LI>Paste</UL><P> This is a Great
      </P>
      <!-- EndFragment-->
      </BODY></HTML>
      The selection, as delimited by StartSelection and EndSelection, is shown in bold.


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
  • Using Dynamic Data Exchange
  • Dynamic Data Exchange Reference


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 Win32-based applications can use to share data. The DDEML provides functions and messages that simplify 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.


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 specified 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 a handle to 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 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 16-bit 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.


Dynamic Data Exchange and Impersonation

To allow a server to impersonate a client, the client calls the DdeSetQualityOfService function. The SECURITY_IMPERSONATION_LEVEL structure is used to control the level of impersonation the server may perform.

A DDE server can impersonate a DDE client by calling the ImpersonateDdeClientWindow function. A DDEML server should use the DdeImpersonateClient function.


Using Dynamic Data Exchange

  • Initiating a conversation
  • Transferring a single item
  • Establishing a permanent data link
  • Carrying out commands in a server application
  • Terminating a 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 to 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.

    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 to 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 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 the system 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 the system. 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))
{

    // Handle errors.

}

When a server responds with a WM_DDE_ACK message, the client application should save a handle to 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 a handle to 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)
{

    // Handle errors.

}

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,
        (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)
{

    // Handle errors.

}

In this example, the server application allocates a memory object to contain the data item. 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 to 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,
        (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)
{

    // Handle errors.

}

Note 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,
        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)
{

    // Handle errors

}

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\0 topic\0 item\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,
        sizeof(DDEDATA) + lstrlen(szItemValue) + 3)))
{
    return;
}
if (!(lpData = (DDEDATA FAR*) GlobalLock(hData)))
{
    GlobalFree(hData);
    return;
}

lpData->fAckReq = bAckRequest;       // as in original WM_DDE_ADVISE
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)
{

    // Handle errors.

}

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)      // check whether flag was set in WM_DDE_ADVISE
{
    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)
{

     // Handle errors.

}

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)
{

    // Handle errors.

}

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,
        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 are associated with dynamic data exchange.

  • Dynamic Data Exchange Functions
  • Dynamic Data Exchange Structures
  • Dynamic Data Exchange Messages


Dynamic Data Exchange Functions

The following functions are used with DDE.

Function | Description
DdeSetQualityOfService | Specifies the quality of service a raw DDE application desires for future DDE conversations it initiates.
FreeDDElParam | Frees the memory specified by the lParam parameter of a posted DDE message.
ImpersonateDdeClientWindow | Enables a DDE server application to impersonate a DDE client application's security context.
PackDDElParam | Packs a DDE lParam value into an internal structure used for sharing DDE data between processes.
ReuseDDElParam | Enables an application to reuse a packed DDE lParam parameter.
UnpackDDElParam | Unpacks a DDE lParam value received from a posted DDE message.


DdeSetQualityOfService

The DdeSetQualityOfService function specifies the quality of service (QOS) a raw DDE application desires for future DDE conversations it initiates. The specified QOS 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 conversation do not affect that conversation's QOS.

BOOL DdeSetQualityOfService(
  HWND hwndClient,                            // handle to window
  CONST SECURITY_QUALITY_OF_SERVICE *pqosNew, // QOS
  PSECURITY_QUALITY_OF_SERVICE pqosPrev       // prior QOS
);

Parameters

hwndClient
[in] Handle to the DDE client window that specifies the source of WM_DDE_INITIATE messages a client will send to start DDE conversations.
pqosNew
[in] Pointer to a SECURITY_QUALITY_OF_SERVICE structure for the desired quality of service values.
pqosPrev
[out] Pointer to a SECURITY_QUALITY_OF_SERVICE structure that receives 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If a quality of service has not been specified for a client window, hwndClient, prior to sending a WM_DDE_INITIATE with the wParam set to hwndClient, the system uses the following default quality of service values for the client window:

{
   Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
   ImpersonationLevel = SecurityImpersonation;
   ContextTrackingMode = SECURITY_STATIC_TRACKING;
   EffectiveOnly = TRUE;
}

Use the DdeSetQualityOfService function to associate a different quality of service with the client window. After you change the quality of service, the new settings affect any subsequent conversations that are started. 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Dde.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Functions, SECURITY_QUALITY_OF_SERVICE, WM_DDE_INITIATE


FreeDDElParam

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
  LPARAM lParam   // lParam of message
);

Parameters

msg
[in] Specifies the posted DDE message.
lParam
[in] Specifies the lParam parameter of the posted DDE message.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Functions, PackDDElParam, ReuseDDElParam, UnpackDDElParam


ImpersonateDdeClientWindow

The ImpersonateDdeClientWindow function enables a DDE server application to impersonate a DDE client application's security context. This protects secure server data from unauthorized DDE clients.

BOOL ImpersonateDdeClientWindow(
  HWND hWndClient,  // handle to DDE client window
  HWND hWndServer   // handle to DDE server window
);

Parameters

hWndClient
[in] Handle to 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
[in] Handle to the DDE server window. An application must create the server window before calling this function.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

Warning If the call to ImpersonateDdeClientWindow fails for any reason, the client is not impersonated and the client request is made in the security context of the calling process. If the calling process is running as a highly privileged account, such as LocalSystem, or as a member of an administrative group, the user may be able to perform actions that would otherwise be disallowed. Therefore it is important that you always check the return value of the call, and if it fails to raise an error, do not continue execution of the client request.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Dde.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Functions, DdeImpersonateClient, RevertToSelf


PackDDElParam

The PackDDElParam function packs a DDE lParam value into an internal structure used for sharing DDE data between processes.

LPARAM PackDDElParam(
  UINT msg,      // DDE message to be posted
  UINT_PTR uiLo, // low-order word of lParam of message
  UINT_PTR uiHi  // high-order word of lParam of message
);

Parameters

msg
[in] Specifies the DDE message to be posted.
uiLo
[in] Specifies a value that corresponds to the 16-bit Windows low-order word of an lParam parameter for the DDE message being posted.
uiHi
[in] Specifies a value that corresponds to the 16-bit Windows high-order word of an lParam parameter for the DDE message being posted.

Return Values

The return value is the lParam value.

Remarks

The return value must be posted as the lParam parameter of a DDE message; it must not be used for any other purpose. After 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 Windows-based applications to Win32-based applications.

An application should call this function only for posted DDE messages.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Functions, FreeDDElParam, ReuseDDElParam, UnpackDDElParam


ReuseDDElParam

The ReuseDDElParam function enables 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.

LPARAM ReuseDDElParam(
  LPARAM lParam,   // posted lParam to be reused
  UINT msgIn,      // received message
  UINT msgOut,     // posted message
  UINT_PTR uiLo,   // low-order word of new lParam
  UINT_PTR uiHi    // high-order word of new lParam
);

Parameters

lParam
[in] Specifies the lParam parameter of the posted DDE message being reused.
msgIn
[in] Specifies the identifier of the received DDE message.
msgOut
[in] Specifies the identifier of the DDE message to be posted. The DDE message will reuse the packed lParam parameter.
uiLo
[in] Specifies the value to be packed into the low-order word of the reused lParam parameter.
uiHi
[in] Specifies the value to be packed into the high-order word of the reused lParam parameter.

Return Values

The return value is the new lParam value.

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Functions, FreeDDElParam, PackDDElParam, UnpackDDElParam


UnpackDDElParam

The UnpackDDElParam function unpacks a DDE lParam value received from a posted DDE message.

BOOL UnpackDDElParam(
  UINT msg,         // posted DDE message
  LPARAM lParam,    // lParam of posted DDE message
  PUINT_PTR puiLo,  // low-order word of lParam
  PUINT_PTR puiHi   // high-order word of lParam
);

Parameters

msg
[in] Specifies the posted DDE message.
lParam
[in] 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.
puiLo
[out] Pointer to a variable that receives the low-order word of lParam.
puiHi
[out] Pointer to a variable that receives the high-order word of lParam.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Remarks

PackDDElParam eases the porting of 16-bit DDE applications to 32-bit DDE applications.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Functions, FreeDDElParam, PackDDElParam, ReuseDDElParam


Dynamic Data Exchange Structures

The following structures are used with DDE.

DDEACK
DDEADVISE
DDEDATA
DDEPOKE
HSZPAIR


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.

typedef struct {
    unsigned short bAppReturnCode:8,
    reserved:6,
    fBusy:1,
    fAck:1;
} DDEACK;

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Structures, WM_DDE_ACK, WM_DDE_ADVISE, WM_DDE_DATA, WM_DDE_EXECUTE, WM_DDE_REQUEST, WM_DDE_POKE, WM_DDE_UNADVISE


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 a handle to a DDEADVISE structure to a server as part of a WM_DDE_ADVISE message.

typedef struct {
    unsigned short reserved:14,
        fDeferUpd:1,
        fAckReq:1;
    short cfFormat;
} DDEADVISE;

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 to 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

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Structures, WM_DDE_ADVISE, WM_DDE_DATA, WM_DDE_UNADVISE


DDEDATA

The DDEDATA structure contains the data, and information about the data, sent as part of a WM_DDE_DATA message.

typedef struct {
    unsigned short unused:12,
        fResponse:1,
        fRelease:1,
        reserved:1,
        fAckReq:1;
    short cfFormat;
    BYTE  Value[1];
} DDEDATA;

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Structures, WM_DDE_ACK, WM_DDE_ADVISE, WM_DDE_DATA, WM_DDE_POKE, WM_DDE_REQUEST


DDEPOKE

The DDEPOKE structure contains the data, and information about the data, sent as part of a WM_DDE_POKE message.

typedef struct {
    unsigned short unused:13,
        fRelease:1,
        fReserved:2;
    short cfFormat;
    BYTE  Value[1];
} DDEPOKE;

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Structures, WM_DDE_POKE


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.

typedef struct tagHSZPAIR {
    HSZ hszSvc;
    HSZ hszTopic;
} HSZPAIR, *PHSZPAIR;

Members

hszSvc
Handle to a service name.
hszTopic
Handle to a topic name.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Structures


Dynamic Data Exchange Messages

The following messages are 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


WM_DDE_ACK

The WM_DDE_ACK message notifies a DDE application of the receipt and processing of the following messages: WM_DDE_POKE, WM_DDE_EXECUTE, WM_DDE_DATA, WM_DDE_ADVISE, WM_DDE_UNADVISE, WM_DDE_INITIATE, or WM_DDE_REQUEST (in some cases).

To post this message, call the PostMessage function with the following parameters.

PostMessage(
  (HWND) hWnd,             // handle to destination window
  WM_DDE_ACK,              // message to send
  (WPARAM) wParam,         // handle to window (HWND)
  (LPARAM) lParam          // message-specific data
);

Parameters

wParam
When responding to WM_DDE_INITIATE, this parameter is a handle to the server window posting the message.

When responding to WM_DDE_EXECUTE, this parameter is a handle to the server window posting the message.

When replying to all other messages, this parameter is a handle to the client or server window posting the message.

lParam
When responding to WM_DDE_INITIATE, the low-order word contains an atom that identifies the replying application. The high-order word contains an atom that identifies the topic for which a conversation is being established.

When responding to WM_DDE_EXECUTE, the low-order word specifies a DDEACK structure containing a series of flags that indicate the status of the response. The high-order word is a handle to a global memory object that contains the command string that was received in the WM_DDE_EXECUTE message.

When replying to all other messages, the low-order word specifies a DDEACK structure containing a series of flags that indicate the status of the response. The high-order word 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 atom, the application posting WM_DDE_ACK can either reuse the 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 lParam 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 global memory object, and the object was sent with the fRelease flags set to FALSE, the application is responsible for deleting the 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. 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.

The application that receives a posted WM_DDE_ACK message must free the lParam parameter by using the FreeDDElParam function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Messages, 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

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.

To post this message, call the PostMessage function with the following parameters.

PostMessage(
  (HWND) hWnd,             // handle to destination window
  WM_DDE_ADVISE,           // message to send
  (WPARAM) wParam,         // handle to client window (HWND)
  (LPARAM) lParam          // advise and item atom
);

Parameters

wParam
Handle to the client window posting the message.
lParam
The low-order word is a handle to a global memory object containing a DDEADVISE structure that specifies how the data is to be sent.

The high-order word 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 the global memory object using the GlobalAlloc function. It allocates the atom using the GlobalAddAtom function.

The client application must create or reuse the WM_DDE_ADVISE lParam parameter by calling the PackDDElParam function or the ReuseDDElParam function.

If the receiving (server) application responds with a negative WM_DDE_ACK message, the posting application must delete the 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 atom or delete it and create a new one. If the WM_DDE_ACK message is positive, the application should delete the global memory object; otherwise, the application should not delete the object.

The server must create or reuse the WM_DDE_ACK lParam parameter by calling the PackDDElParam function or the ReuseDDElParam function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Messages, DDEADVISE, FreeDDElParam, GlobalAddAtom, GlobalAlloc, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK, WM_DDE_DATA, WM_DDE_POKE, WM_DDE_REQUEST


WM_DDE_DATA

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.

To post this message, call the PostMessage function with the following parameters.

PostMessage(
  (HWND) hWnd,             // handle to destination window
  WM_DDE_DATA,             // message to send
  (WPARAM) wParam,         // handle to server window (HWND)
  (LPARAM) lParam          // data and item atom
);

Parameters

wParam
Handle to the server window posting the message.
lParam
The low-order word is a handle to 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.

The high-order word contains an atom that identifies the data item for which the data or notification is sent.

Remarks

Posting

The server application allocates the global memory object using the GlobalAlloc function. It allocates the atom using the GlobalAddAtom function.

The server must create or reuse the WM_DDE_DATA lParam parameter by calling the PackDDElParam function or the ReuseDDElParam function.

If the receiving (client) application responds with a negative WM_DDE_ACK message, the posting (server) application must delete the global memory object; otherwise, the client must delete the 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 the object 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 the object.

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 atom, or it can delete it and create a new one.

The client must create or reuse the WM_DDE_ACK lParam parameter by calling the PackDDElParam function or the ReuseDDElParam function.

If fAckReq is FALSE, the client application should delete the atom.

If the posting application specified global memory object as NULL, the receiving 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 the global memory object is not NULL, the client should free the object, 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Messages, DDEDATA, FreeDDElParam, GlobalAddAtom, GlobalAlloc, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK, WM_DDE_ADVISE, WM_DDE_POKE, WM_DDE_REQUEST


WM_DDE_EXECUTE

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.

To post this message, call the PostMessage function with the following parameters.

PostMessage(
  (HWND) hWnd,             // handle to destination window
  WM_DDE_EXECUTE,          // message to send
  (WPARAM) wParam,         // handle to client window (HWND)
  (LPARAM) lParam          // command string (LPCTSTR)
);

Parameters

wParam
Handle to the client window posting the message.
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.

The following are 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 allocates the global memory object by calling the GlobalAlloc function.

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 object returned by 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 global memory 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Messages, GlobalAlloc, IsWindowUnicode, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK


WM_DDE_INITIATE

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.)

To send this message, call the SendMessage function with the following parameters.

SendMessage(
  (HWND) hWnd,             // handle to destination window
  WM_DDE_INITIATE,         // message to send
  (WPARAM) wParam,         // handle to client window (HWND)
  (LPARAM) lParam          // application and topic atom
);

Parameters

wParam
Handle to the client window sending the message.
lParam
The low-order word 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 this parameter is NULL, a conversation with all applications is requested.

The high-order word 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 the low-order word of lParam is NULL, any server application can respond. If the high-order word of lParam is NULL, any topic is valid. Upon receiving a WM_DDE_INITIATE request with the high-order word of the lParam parameter set to NULL, a server must send a WM_DDE_ACK message for each of the topics it supports.

Sending

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 atoms by calling the GlobalAddAtom function.

When SendMessage returns, the client application must delete the 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 atoms; it should not reuse the atoms sent with WM_DDE_INITIATE.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Messages, GlobalAddAtom, GlobalAlloc, PostMessage, SendMessage, WM_DDE_ACK


WM_DDE_POKE

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.

To post this message, call the PostMessage function with the following parameters.

PostMessage(
  (HWND) hWnd,             // handle to destination window
  WM_DDE_POKE,             // message to send
  (WPARAM) wParam,         // handle to client window (HWND)
  (LPARAM) lParam          // data and item atom
);

Parameters

wParam
Handle to the client window posting the message.
lParam
The low-order word is a handle to a global memory object containing a DDEPOKE structure with the data and additional information.

The high-order word contains a global atom that identifies the data item for which the data or notification is being sent.

Remarks

Posting

The client application must allocate memory for the global memory object using the GlobalAlloc function. The client application must delete the 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 atom using the GlobalAddAtom function.

The client application must create or reuse the WM_DDE_POKE lParam parameter by calling the PackDDElParam function or the ReuseDDElParam function.

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 atom, or it can delete it and create a new one.

The server must create or reuse the WM_DDE_ACK lParam parameter by calling the PackDDElParam function or the ReuseDDElParam function.

To free the global memory 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 the object 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 object, the server should call the FreeDDElParam function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Messages, DDEPOKE, DeleteMetaFile, FreeDDElParam, GlobalAddAtom, GlobalAlloc, GlobalFree, METAFILEPICT, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK


WM_DDE_REQUEST

A DDE client application posts a WM_DDE_REQUEST message to a DDE server application to request the value of a data item.

To post this message, call the PostMessage function with the following parameters.

PostMessage(
  (HWND) hWnd,             // handle to destination window
  WM_DDE_REQUEST,          // message to send
  (WPARAM) wParam,         // handle to client window (HWND)
  (LPARAM) lParam          // format and item atom
);

Parameters

wParam
Handle to the client window sending the message.
lParam
The low-order word specifies a standard or registered clipboard format.

The high-order word contains an atom that identifies the data item requested from the server.

Remarks

Posting

The client application allocates the atom 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 atom or it can delete the atom and create a new one.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Messages, GlobalAddAtom, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK, WM_DDE_DATA


WM_DDE_TERMINATE

A DDE application (client or server) posts a WM_DDE_TERMINATE message to terminate a conversation.

To post this message, call the PostMessage function with the following parameters.

PostMessage(
  (HWND) hWnd,            // handle to destination window
  WM_DDE_TERMINATE,       // message to send
  (WPARAM) wParam,        // handle to posting window (HWND)
  (LPARAM) lParam         // not used; must be zero
);

Parameters

wParam
Handle to the client or server window posting the message.
lParam
This parameter is not used.

Remarks

Posting

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 global memory objects associated with WM_DDE_POKE or WM_DDE_DATA messages that do not have the fRelease member set.

Receiving

The client or server application should respond by posting a WM_DDE_TERMINATE message.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Messages, PostMessage, SendMessage, WM_DDE_DATA, WM_DDE_POKE


WM_DDE_UNADVISE

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.

To post this message, call the PostMessage function with the following parameters.

PostMessage(
  (HWND) hWnd,             // handle to destination window
  WM_DDE_UNADVISE,         // message to send
  (WPARAM) wParam,         // handle to client window (HWND)
  (LPARAM) lParam          // format and item atom
);

Parameters

wParam
Handle to the client window sending the message.
lParam
The low-order word specifies the clipboard format of the item for which the update request is being retracted. If this is NULL, all active WM_DDE_ADVISE conversations for the item are to be terminated.

The high-order word contains a global atom that identifies the item for which the update request is being retracted. If this is NULL, all active WM_DDE_ADVISE links associated with the conversation are to be terminated.

Remarks

The client application allocates the high-order word of lParam by calling the GlobalAddAtom function.

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 atom, or it can delete the atom and create a new one.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Dde.h; include Windows.h.

See Also

Dynamic Data Exchange Overview, Dynamic Data Exchange Messages, GlobalAddAtom, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK, WM_DDE_ADVISE


Dynamic Data Exchange Management Library

Dynamic data exchange (DDE) is a form of interprocess communication 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
  • Dynamic Data Exchange Management Reference


About the DDEML

DDE differs from the clipboard data-transfer mechanism. One difference is that the clipboard is almost always used as a one-time response to a specific action by the user — such as clicking Paste from a menu. Although DDE can also be initiated by a user, it typically continues without the user's further involvement.

The dynamic data exchange management library (DDEML) provides an interface 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 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 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

These concepts are key to understanding DDE and the DDEML.

  • Client and Server Interaction
  • Transactions and the DDE Callback Function
  • Service Names, Topic Names, and Item Names
  • System Topic
  • Initialization
  • Callback Function
  • String Management
  • DDEML and Threads


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 can 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 can 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 can 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.


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 in the DdeInitialize ufCmd parameter. 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 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, // pointer to 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. For more information, please see DdeCallback.

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 to conversation
HSZ hsz1;         // handle to string
HSZ hsz2;         // handle to string
HDDEDATA hdata;   // handle to 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 DWORD 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 !

To compare the values of two string handles, use the DdeCmpStringHandles function.

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 to 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 atom manager and are subject to the same size restrictions as are atoms.


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.


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 following topics describe the name service.

  • Service Name Registration
  • Service Name Filter


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 following topics describe how an application establishes new conversations and gets information about existing conversations.

  • Single Conversations
  • Multiple 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 DWORD 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.

// Here is the connect case.

    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, // pointer 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 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 DWORD 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 to 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 to 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 to 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 following topics describe the types of transactions that clients can use to interact with a server.

  • Request Transaction
  • Poke Transaction
  • Advise Transaction
  • Execute Transaction
  • Synchronous and Asynchronous Transactions
  • Transaction Control
  • Transaction Classes
  • Transaction Types


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 can 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 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 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,        // pointer 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 to 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 Reference

The following elements are used to manage dynamic data exchange.

  • Dynamic Data Exchange Management Functions
  • Dynamic Data Exchange Management Structures
  • Dynamic Data Exchange Management Transactions


Dynamic Data Exchange Management Functions

The following functions are used to manage dynamic data exchange.

Function | Description
DdeAbandonTransaction | Abandons the specified asynchronous transaction and releases all resources associated with the transaction.
DdeAccessData | Provides access to the data in the specified dynamic data exchange (DDE) object.
DdeAddData | Adds data to the specified dynamic data exchange (DDE) object.
DdeCallback | An application-defined callback function used with the DDEML functions.
DdeClientTransaction | Begins a data transaction between a client and a server.
DdeCmpStringHandles | Compares the values of two string handles.
DdeConnect | Establishes a conversation with a server application that supports the specified service name and topic name pair.
DdeConnectList | Establishes a conversation with all server applications that support the specified service name and topic name pair.
DdeCreateDataHandle | Creates a DDE object and fills the object with data from the specified buffer.
DdeCreateStringHandle | Creates a handle that identifies the specified string.
DdeDisconnect | Terminates a DDE conversation.
DdeDisconnectList | Destroys the specified conversation list and terminates all conversations associated with the list.
DdeEnableCallback | Enables or disables transactions for a specific conversation or for all conversations currently established by the calling application.
DdeFreeDataHandle | Frees a DDE object and deletes the data handle associated with the object.
DdeFreeStringHandle | Frees a string handle in the calling application.
DdeGetData | Copies data from the specified DDE object to the specified local buffer.
DdeGetLastError | Retrieves the most recent error code set by the failure of a DDEML function.
DdeImpersonateClient | Impersonates a DDE client application in a DDE client conversation.
DdeInitialize | Registers an application with DDEML.
DdeKeepStringHandle | Increments the usage count associated with the specified handle.
DdeNameService | Registers or unregisters the service names a DDE server supports.
DdePostAdvise | Causes the system to send an XTYPE_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.
DdeQueryConvInfo | Retrieves information about a DDE transaction and about the conversation in which the transaction takes place.
DdeQueryNextServer | Retrieves the next conversation handle in the specified conversation list.
DdeQueryString | Copies text associated with a string handle into a buffer.
DdeReconnect | Enables a client DDEML application to attempt to reestablish a conversation with a service that has terminated a conversation with the client.
DdeSetUserHandle | Associates an application-defined value with a conversation handle or a transaction identifier.
DdeUnaccessData | Unaccesses a DDE object.
DdeUninitialize | Frees all DDEML resources associated with the calling application.


DdeAbandonTransaction

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 to conversation
  DWORD idTransaction   // transaction identifier
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
hConv
[in] Handle to 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
[in] Specifies the identifier of the transaction to abandon. If this parameter is 0L, all active transactions in the specified conversation are abandoned.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Errors

The DdeGetLastError function can be used to get the error code, which can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeClientTransaction, DdeInitialize, DdeQueryConvInfo


DdeAccessData

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 to DDE object
  LPDWORD pcbDataSize  // receives data length
);

Parameters

hData
[in] Handle to the DDE object to access.
pcbDataSize
[out] Pointer 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 Values

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 code, which can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeAddData, DdeCreateDataHandle, DdeFreeDataHandle, DdeUnaccessData


DdeAddData

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 to DDE data object
  LPBYTE pSrc,     // pointer to source buffer
  DWORD cb,        // length of data
  DWORD cbOff      // offset within DDE data object
);

Parameters

hData
[in] Handle to the DDE object that receives additional data.
pSrc
[in] Pointer to a buffer containing the data to add to the DDE object.
cb
[in] Specifies the length, in bytes, of the data to be added to the DDE object, including the terminating NULL, if the data is a string.
cbOff
[in] 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 Values

If the function succeeds, the return value is a new handle to 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 code, which can 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 can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeAccessData, DdeCreateDataHandle, DdeUnaccessData


DdeCallback

The DdeCallbackProc function is an application-defined callback function used with the Dynamic Data Exchange Management Library (DDEML) functions. It processes dynamic data exchange (DDE) transactions. The PFNCALLBACK type defines a pointer to this callback function. DdeCallback is a placeholder for the application-defined function name.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,         // transaction type
  UINT uFmt,          // clipboard data format
  HCONV hconv,        // handle to the conversation
  HSZ hsz1,           // handle to a string
  HSZ hsz2,           // handle to a string
  HDDEDATA hdata,     // handle to a global memory object
  ULONG_PTR dwData1,  // transaction-specific data
  ULONG_PTR dwData2   // transaction-specific data
);

Parameters

uType
[in] 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
[in] Specifies the format in which data is sent or received.
hconv
[in] Handle to the conversation associated with the current transaction.
hsz1
[in] Handle to 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
[in] Handle to 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
[in] Handle to 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
[in] Specifies transaction-specific data. For the meaning of this parameter, see the description of the transaction type.
dwData2
[in] Specifies transaction-specific data. For the meaning of this parameter, see the description of the transaction type.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeEnableCallback, DdeInitialize


DdeClientTransaction

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,       // pointer to data to pass to server
  DWORD cbData,       // length of data
  HCONV hConv,        // handle to conversation
  HSZ hszItem,        // handle to item name string
  UINT wFmt,          // clipboard data format
  UINT wType,         // transaction type
  DWORD dwTimeout,    // time-out duration
  LPDWORD pdwResult   // pointer to transaction result
);

Parameters

pData
[in] Pointer 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 -1. 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
[in] Specifies the length, in bytes, of the data pointed to by the pData parameter, including the terminating NULL, if the data is a string. A value of -1 indicates that pData is a data handle that identifies the data being sent.
hConv
[in] Handle to the conversation in which the transaction is to take place.
hszItem
[in] Handle to 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
[in] 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
[in] Specifies the transaction type. This parameter can be one of the following values.
Value | 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
[in] 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
[out] Pointer 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 Values

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 code, which can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeAbandonTransaction, DdeAccessData, DdeConnect, DdeConnectList, DdeCreateDataHandle, DdeCreateStringHandle, DdeFreeDataHandle, XTYP_ADVSTART, XTYP_ADVSTOP, XTYP_EXECUTE, XTYP_POKE, XTYP_REQUEST


DdeCmpStringHandles

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 to first string
  HSZ hsz2   // handle to second string
);

Parameters

hsz1
[in] Handle to the first string.
hsz2
[in] Handle to the second string.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeAccessData, DdeCreateStringHandle, DdeFreeStringHandle


DdeConnect

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 to service name string
  HSZ hszTopic,      // handle to topic name string
  PCONVCONTEXT pCC   // context data
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
hszService
[in] Handle to 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
[in] Handle to 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
[in] Pointer 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 Values

If the function succeeds, the return value is the handle to the established conversation.

If the function fails, the return value is 0L.

Errors

The DdeGetLastError function can be used to get the error code, which can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, CONVCONTEXT, DdeConnectList, DdeCreateStringHandle, DdeDisconnect, DdeDisconnectList, DdeInitialize, XTYP_REGISTER, XTYP_UNREGISTER


DdeConnectList

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 to service name string
  HSZ hszTopic,         // handle to topic name string
  HCONVLIST hConvList,  // handle to conversation list
  PCONVCONTEXT pCC      // context data
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
hszService
[in] Handle to 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
[in] Handle to 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
[in] Handle to the conversation list to be enumerated. This parameter should be 0L if a new conversation list is to be established.
pCC
[in] Pointer 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 Values

If the function succeeds, the return value is the handle to a new conversation list.

If the function fails, the return value is 0L. The handle to the old conversation list is no longer valid.

Errors

The DdeGetLastError function can be used to get the error code, which can 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 the DdeConnectList function, regardless of whether any conversation handles within the list are active. To free the handle, an application can call DdeDisconnectList.

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, CONVCONTEXT, DdeConnect, DdeCreateStringHandle, DdeDisconnect, DdeDisconnectList, DdeInitialize, DdeQueryNextServer


DdeCreateDataHandle

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,  // pointer to source buffer
  DWORD cb,     // length of DDE object
  DWORD cbOff,  // offset from beginning of source buffer
  HSZ hszItem,  // handle to item name string
  UINT wFmt,    // clipboard data format
  UINT afCmd    // creation flags
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
pSrc
[in] Pointer 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
[in] Specifies the amount of memory, in bytes, to copy from the buffer pointed to by pSrc. (include the terminating NULL, if the data is a string). If this parameter is zero, the pSrc parameter is ignored.
cbOff
[in] 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
[in] Handle to 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
[in] Specifies the standard clipboard format of the data.
afCmd
[in] 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 Values

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 code, which can 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 can be used only for read access to the DDE object identified by the handle.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeAccessData, DdeCreateStringHandle, DdeFreeDataHandle, DdeGetData, DdeInitialize


DdeCreateStringHandle

The DdeCreateStringHandle function creates a handle that identifies the specified string. 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,    // pointer to null-terminated string
  int iCodePage  // code page identifier
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
psz
[in] Pointer to a buffer that contains the null-terminated string for which a handle is to be created. This string can be up to 255 characters. The reason for this limit is that DDEML string management functions are implemented using global atoms.
iCodePage
[in] 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 Values

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 code, which can 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 !

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeAccessData, DdeCmpStringHandles, DdeFreeStringHandle, DdeInitialize, DdeKeepStringHandle, DdeQueryString


DdeDisconnect

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 to conversation
);

Parameters

hConv
[in/out] Handle to the active conversation to be terminated.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Errors

The DdeGetLastError function can be used to get the error code, which can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeConnect, DdeConnectList, DdeDisconnectList, XTYP_DISCONNECT


DdeDisconnectList

The DdeDisconnectList function destroys the specified conversation list and terminates all conversations associated with the list.

BOOL DdeDisconnectList(
  HCONVLIST hConvList   // handle to conversation list
);

Parameters

hConvList
[in] Handle to the conversation list. This handle must have been created by a previous call to the DdeConnectList function.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Errors

The DdeGetLastError function can be used to get the error code, which can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeConnect, DdeConnectList, DdeDisconnect


DdeEnableCallback

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 to conversation
  UINT wCmd     // enable or disable function code
);

Parameters

idInst
[in] Specifies the application-instance identifier obtained by a previous call to the DdeInitialize function.
hConv
[in] Handle to the conversation to enable or disable. If this parameter is NULL, the function affects all conversations.
wCmd
[in] 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

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 code, which can be one of the following values:

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 function returns a nonzero, 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 zero, an application should always process messages in a timely manner.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeConnect, DdeConnectList, DdeDisconnect, DdeInitialize


DdeFreeDataHandle

The DdeFreeDataHandle function frees a dynamic data exchange (DDE) object and deletes the data handle associated with the object.

BOOL DdeFreeDataHandle(
  HDDEDATA hData   // handle to DDE object
);

Parameters

hData
[in/out] Handle to 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Errors

The DdeGetLastError function can be used to get the error code, which can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeAccessData, DdeCreateDataHandle, DdeClientTransaction


DdeFreeStringHandle

The DdeFreeStringHandle function frees a string handle in the calling application.

BOOL DdeFreeStringHandle(
  DWORD idInst,  // instance identifier
  HSZ hsz        // handle to string
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
hsz
[in/out] Handle to the string handle to be freed. This handle must have been created by a previous call to the DdeCreateStringHandle function.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, CONVINFO, DdeCmpStringHandles, DdeCreateStringHandle, DdeInitialize, DdeKeepStringHandle, DdeQueryConvInfo, DdeQueryString


DdeGetData

The DdeGetData function copies data from the specified dynamic data exchange (DDE) object to the specified local buffer.

DWORD DdeGetData(
  HDDEDATA hData,  // handle to DDE  object
  LPBYTE pDst,     // pointer to destination buffer
  DWORD cbMax,     // amount of data to copy
  DWORD cbOff      // offset to beginning of data
);

Parameters

hData
[in] Handle to the DDE object that contains the data to copy.
pDst
[out] Pointer 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
[in] 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
[in] Specifies an offset within the DDE object. Data is copied from the object beginning at this offset.

Return Values

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 code, which can be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeAccessData, DdeCreateDataHandle, DdeFreeDataHandle


DdeGetLastError

The DdeGetLastError function retrieves the most recent error code set by the failure of a Dynamic Data Exchange Management Library (DDEML) function and resets the error code to DMLERR_NO_ERROR.

UINT DdeGetLastError(
  DWORD idInst   // instance identifier
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

Return Values

If the function succeeds, the return value is the last error code, which can be one of the following 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeEnableCallback, DdeInitialize, PostMessage


DdeImpersonateClient

The DdeImpersonateClient function impersonates a dynamic data exchange (DDE) client application in a DDE client conversation.

BOOL DdeImpersonateClient(
  HCONV hConv   // handle to DDE conversation
);

Parameters

hConv
[in] Handle to the DDE client conversation to be impersonated.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, ImpersonateNamedPipeClient, RevertToSelf


DdeInitialize

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,          // instance identifier
  PFNCALLBACK pfnCallback,  // callback function
  DWORD afCmd,              // command and filter flags
  DWORD ulRes               // reserved
);

Parameters

pidInst
[in/out] Pointer 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
[in] Pointer 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
[in] 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 one or more of the following values.
Value | 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 Values

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 DdeInitialize. 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 CONVCONTEXT structure (CP_WINANSI or CP_WINUNICODE).

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions


DdeKeepStringHandle

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 to string
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
hsz
[in/out] Handle to the string handle to be saved.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, CONVINFO, DdeCreateStringHandle, DdeFreeStringHandle, DdeInitialize, DdeQueryConvInfo, DdeQueryString


DdeNameService

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 to service name string
  HSZ hsz2,      // reserved
  UINT afCmd     // service name flags
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
hsz1
[in] Handle to 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
[in] Specifies the service name options. This parameter can be one of the following values.
Value | Meaning
DNS_REGISTER | Registers the error code service name.
DNS_UNREGISTER | Unregisters the error code 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 Values

If the function 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 code, which can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeConnect, DdeConnectList, DdeInitialize, XTYP_REGISTER, XTYP_UNREGISTER


DdePostAdvise

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 to topic name string
  HSZ hszItem   // handle to item name string
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
hszTopic
[in] Handle to 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
[in] Handle to 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Errors

The DdeGetLastError function can be used to get the error code, which can 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 can result.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeInitialize, XTYP_ADVREQ


DdeQueryConvInfo

The DdeQueryConvInfo function retrieves information about a dynamic data exchange (DDE) transaction and about the conversation in which the transaction takes place.

UINT DdeQueryConvInfo(
  HCONV hConv,          // handle to conversation
  DWORD idTransaction,  // transaction identifier
  PCONVINFO pConvInfo   // conversation data
);

Parameters

hConv
[in] Handle to the conversation.
idTransaction
[in] 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
[in/out] Pointer 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 Values

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 code, which can 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, CONVINFO, DdeClientTransaction, DdeConnect, DdeConnectList, DdeKeepStringHandle, DdeQueryNextServer


DdeQueryNextServer

The DdeQueryNextServer function retrieves the next conversation handle in the specified conversation list.

HCONV DdeQueryNextServer(
  HCONVLIST hConvList,  // handle to conversation list
  HCONV hConvPrev       // previous conversation handle
);

Parameters

hConvList
[in] Handle to the conversation list. This handle must have been created by a previous call to the DdeConnectList function.
hConvPrev
[in] Handle to the conversation handle previously returned by this function. If this parameter is 0L, the function returns the first conversation handle in the list.

Return Values

If the list contains any more conversation handles, the return value is the next conversation handle in the list; otherwise, it is 0L.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeConnectList, DdeDisconnectList


DdeQueryString

The DdeQueryString function copies text associated with a string handle into a buffer.

DWORD DdeQueryString(
  DWORD idInst,  // instance identifier
  HSZ hsz,       // handle to string
  LPTSTR psz,    // pointer to destination buffer
  DWORD cchMax,  // length of buffer
  int iCodePage  // code page identifier
);

Parameters

idInst
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.
hsz
[in] Handle to the string to copy. This handle must have been created by a previous call to the DdeCreateStringHandle function.
psz
[in/out] Pointer to a buffer that receives the string. To obtain the length of the string, this parameter should be set to NULL.
cchMax
[in] Specifies the length, in TCHARs, of the buffer pointed to by the psz parameter. For the ANSI version of the function, this is the number of bytes; for the Unicode version, this is the number of characters. 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
[in] Specifies the code page used to render the string. This value should be either CP_WINANSI or CP_WINUNICODE.

Return Values

If the psz parameter specified a valid pointer, the return value is the length, in TCHARs, 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, the DdeQueryString function obtains the length, in bytes, of the string associated with the string handle. The length does not include the terminating null character.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeCmpStringHandles, DdeCreateStringHandle, DdeFreeStringHandle, DdeInitialize


DdeReconnect

The DdeReconnect function enables 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 to conversation to reestablish
);

Parameters

hConv
[in] Handle to 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 Values

If the function succeeds, the return value is the handle to the reestablished conversation.

If the function fails, the return value is 0L.

Errors

The DdeGetLastError function can be used to get the error code, which can be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_CONV_ESTABLISHED
DMLERR_NO_ERROR

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeConnect, DdeDisconnect


DdeSetUserHandle

The DdeSetUserHandle function associates an application-defined 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 to conversation
  DWORD id,         // transaction identifier
  DWORD_PTR hUser   // application-defined value
);

Parameters

hConv
[in] Handle to the conversation.
id
[in] 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
[in] Value to associate with the conversation handle.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Errors

The DdeGetLastError function can be used to get the error code, which can be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR
DMLERR_UNFOUND_QUEUE_ID

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeQueryConvInfo


DdeUnaccessData

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 to DDE object
);

Parameters

hData
[in] Handle to the DDE object.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Errors

The DdeGetLastError function can be used to get the error code, which can be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeAccessData, DdeAddData, DdeCreateDataHandle, DdeFreeDataHandle


DdeUninitialize

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
[in] Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Remarks

DdeUninitialize terminates any conversations currently open for the application.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Library: Use User32.lib.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Functions, DdeDisconnect, DdeDisconnectList, DdeInitialize


Dynamic Data Exchange Management Structures

The following structures are used to manage dynamic data exchange.

CONVCONTEXT
CONVINFO
DDEML_MSG_HOOK_DATA
MONCBSTRUCT
MONCONVSTRUCT
MONERRSTRUCT
MONHSZSTRUCT
MONLINKSTRUCT
MONMSGSTRUCT


CONVCONTEXT

The CONVCONTEXT structure contains information supplied by a DDE client application. The information is useful for specialized or cross-language DDE conversations.

typedef struct tagCONVCONTEXT {
  UINT  cb;
  UINT  wFlags;
  UINT  wCountryID;
  int   iCodePage;
  DWORD dwLangID;
  DWORD dwSecurity;
  SECURITY_QUALITY_OF_SERVICE qos;
} CONVCONTEXT, *PCONVCONTEXT;

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Structures


CONVINFO

The CONVINFO structure contains information about a DDE conversation.

typedef struct tagCONVINFO {
  DWORD       cb;
  DWORD_PTR   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, *PCONVINFO;

Members

cb
Specifies the structure's size, in bytes.
hUser
Application-defined data.
hConvPartner
Handle to 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
Handle to the service name of the partner application.
hszServiceReq
Handle to the service name of the server application that was requested for connection.
hszTopic
Handle to the name of the requested topic.
hszItem
Handle to 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 one or more 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
Handle to the conversation list if the handle to 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
Handle to the window of the calling application involved in the conversation.
hwndPartner
Handle to the window of the partner application involved in the current conversation.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Structures, CONVCONTEXT, DdeInitialize, DdePostAdvise, DdeQueryConvInfo


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.

typedef struct tagDDEML_MSG_HOOK_DATA {
  UINT_PTR uiLo;
  UINT_PTR uiHi;
  DWORD cbData;
  DWORD Data[8];
} DDEML_MSG_HOOK_DATA, *PDDEML_MSG_HOOK_DATA;

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)).

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Structures, MONCBSTRUCT, MONCONVSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


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.

typedef struct tagMONCBSTRUCT {
  UINT   cb;
  DWORD  dwTime;
  HANDLE hTask;
  DWORD  dwRet;
  UINT   wType;
  UINT   wFmt;
  HCONV  hConv;
  HSZ    hsz1;
  HSZ    hsz2;
  HDDEDATA hData;
  ULONG_PTR dwData1;
  ULONG_PTR dwData2;
  CONVCONTEXT cc;
  DWORD  cbData;
  DWORD  Data[8];
} MONCBSTRUCT, *PMONCBSTRUCT;

Members

cb
Specifies the structure's size, in bytes.
dwTime
Specifies the Windows time at which the transaction occurred. Windows time is the number of milliseconds that have elapsed since the system was booted.
hTask
Handle to 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
Specifies the transaction type.
wFmt
Specifies the format of the data exchanged (if any) during the transaction.
hConv
Handle to the conversation in which the transaction took place.
hsz1
Handle to a string.
hsz2
Handle to a string.
hData
Handle to 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 can be more than 32 bytes.
Data
Contains the first 32 bytes of data being passed with the transaction
(8 * sizeof(DWORD)).

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Structures, CONVCONTEXT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


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.

typedef struct tagMONCONVSTRUCT {
  UINT   cb;
  BOOL   fConnect;
  DWORD  dwTime;
  HANDLE hTask;
  HSZ    hszSvc;
  HSZ    hszTopic;
  HCONV  hConvClient;
  HCONV  hConvServer;
} MONCONVSTRUCT, *PMONCONVSTRUCT;

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
Handle to a task (application instance) that is a partner in the conversation.
hszSvc
Handle to the service name on which the conversation is established.
hszTopic
Handle to the topic name on which the conversation is established.
hConvClient
Handle to the client conversation.
hConvServer
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Structures, MONCBSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


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.

typedef struct tagMONERRSTRUCT {
  UINT   cb;
  UINT   wLastError;
  DWORD  dwTime;
  HANDLE hTask;
} MONERRSTRUCT, *PMONERRSTRUCT;

Members

cb
Specifies the structure's size, in bytes.
wLastError
Specifies the current error.
dwTime
Specifies the Windows time at which the error occurred. Windows time is the number of milliseconds that have elapsed since the system was booted.
hTask
Handle to the task (application instance) that called the DDE function that caused the error.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Structures, MONCBSTRUCT, MONCONVSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


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.

typedef struct tagMONHSZSTRUCT {
  UINT   cb;
  BOOL   fsAction;
  DWORD  dwTime;
  HSZ    hsz;
  HANDLE hTask;
  TCHAR   str[1];
} MONHSZSTRUCT, *PMONHSZSTRUCT;

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 at which 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
Handle to the string. Because string handles are local to the process, this member is a global atom.
hTask
Handle to the task (application instance) performing the action on the string handle.
str
Pointer to the string identified by the hsz member.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Structures, MONCBSTRUCT, MONCONVSTRUCT, MONERRSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


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.

typedef struct tagMONLINKSTRUCT {
  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, *PMONLINKSTRUCT;

Members

cb
Specifies the structure's size, in bytes.
dwTime
Specifies the Windows time at which the advise loop was started or ended. Windows time is the number of milliseconds that have elapsed since the system was booted.
hTask
Handle to 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
Handle to the service name of the server in the advise loop.
hszTopic
Handle to the topic name on which the advise loop is established.
hszItem
Handle to 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
Handle to the server conversation.
hConvClient
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Structures, MONCBSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONMSGSTRUCT


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.

typedef struct tagMONMSGSTRUCT {
  UINT   cb;
  HWND   hwndTo;
  DWORD  dwTime;
  HANDLE hTask;
  UINT   wMsg;
  WPARAM wParam;
  LPARAM lParam;
  DDEML_MSG_HOOK_DATA dmhd;
} MONMSGSTRUCT, *PMONMSGSTRUCT;

Members

cb
Specifies the structure's size, in bytes.
hwndTo
Handle to 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
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Structures, DDEML_MSG_HOOK_DATA, MONCBSTRUCT, MONCONVSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT


Dynamic Data Exchange Management Transactions

The following transactions are used to manage dynamic data exchange.

XTYP_ADVDATA
XTYP_ADVREQ
XTYP_ADVSTART
XTYP_ADVSTOP
XTYP_CONNECT
XTYP_CONNECT_CONFIRM
XTYP_DISCONNECT
XTYP_ERROR
XTYP_EXECUTE
XTYP_MONITOR
XTYP_POKE
XTYP_REGISTER
XTYP_REQUEST
XTYP_UNREGISTER
XTYP_WILDCONNECT
XTYP_XACT_COMPLETE


XTYP_ADVDATA

The XTYP_ADVDATA transaction informs the client that the value of the data item has changed. The DDE client callback function, DdeCallback, receives this transaction after establishing an advise loop with a server.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_ADVDATA
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Specifies the format atom of the data sent from the server.
hconv
Handle to the conversation.
hsz1
Handle to the topic name.
hsz2
Handle to the item name.
hdata
Handle to 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 Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeClientTransaction, DdeGetData, DdePostAdvise


XTYP_ADVREQ

The XTYP_ADVREQ 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. The system sends this transaction to the DDE callback function, DdeCallback, after the server calls the DdePostAdvise function.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_ADREQ
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Specifies the format in which the data should be submitted to the client.
hconv
Handle to the conversation.
hsz1
Handle to the topic name.
hsz2
Handle to 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 Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeCreateDataHandle, DdeInitialize, DdePostAdvise


XTYP_ADVSTART

A client uses the XTYP_ADVSTART transaction to establish an advise loop with a server. A DDE server callback function, DdeCallback, receives this transaction when a client specifies XTYP_ADVSTART as the uType parameter of the DdeClientTransaction function.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_ADVSTART
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Specifies the data format requested by the client.
hconv
Handle to the conversation.
hsz1
Handle to the topic name.
hsz2
Handle to the item name.
hdata
Not used.
dwData1
Not used.
dwData2
Not used.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeClientTransaction, DdeInitialize, DdePostAdvise


XTYP_ADVSTOP

A client uses the XTYP_ADVSTOP transaction to end an advise loop with a server. A DDE server callback function, DdeCallback, receives this transaction when a client specifies XTYP_ADVSTOP in the DdeClientTransaction function.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_ADVSTOP
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Specifies the data format associated with the advise loop being ended.
hconv
Handle to the conversation.
hsz1
Handle to the topic name.
hsz2
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeClientTransaction, DdeInitialize, DdePostAdvise


XTYP_CONNECT

A client uses the XTYP_CONNECT transaction to establish a conversation. A DDE server callback function, DdeCallback, receives this 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.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_CONNECT
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Not used.
hconv
Not used.
hsz1
Handle to the topic name.
hsz2
Handle to the service name.
hdata
Not used.
dwData1
Pointer 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 Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, CONVCONTEXT, DdeConnect, DdeInitialize


XTYP_CONNECT_CONFIRM

A DDE server callback function, DdeCallback, 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.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_CONNECT_CONFIRM
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Not used.
hconv
Handle to the new conversation.
hsz1
Handle to the topic name on which the conversation has been established.
hsz2
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeConnect, DdeConnectList, DdeInitialize


XTYP_DISCONNECT

An application's DDE callback function, DdeCallback, receives the XTYP_DISCONNECT transaction when the application's partner in a conversation uses the DdeDisconnect function to terminate the conversation.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_DISCONNECT
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Not used.
hconv
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeDisconnect, DdeInitialize, DdeQueryConvInfo


XTYP_ERROR

A DDE callback function, DdeCallback, receives the XTYP_ERROR transaction when a critical error occurs.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_ERROR
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Not used.
hconv
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions


XTYP_EXECUTE

A client uses the XTYP_EXECUTE transaction to send a command string to the server. A DDE server callback function, DdeCallback, receives this transaction when a client specifies XTYP_EXECUTE in the DdeClientTransaction function.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_EXECUTE
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Not used.
hconv
Handle to the conversation.
hsz1
Handle to the topic name.
hsz2
Not used.
hdata
Handle to the command string.
dwData1
Not used.
dwData2
Not used.

Return Values

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 synchronously, 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeClientTransaction, DdeGetData, DdeInitialize


XTYP_MONITOR

A DDE debugger's DDE callback function, DdeCallback, receives the XTYP_MONITOR transaction whenever a DDE event occurs in the system. To receive this transaction, an application must specify the APPCLASS_MONITOR value when it calls the DdeInitialize function.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_MONITOR
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Not used.
hconv
Not used.
hsz1
Not used.
hsz2
Not used.
hdata
Handle to 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
Specifies the DDE event. This parameter can 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 Values

If the callback function processes this transaction, it should return 0.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeAccessData, DdeInitialize, DdeUninitialize, MONCBSTRUCT, MONCONVSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


XTYP_POKE

A client uses the XTYP_POKE transaction to send unsolicited data to the server. A DDE server callback function, DdeCallback, receives this transaction when a client specifies XTYP_POKE in DdeClientTransaction function.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_POKE
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Specifies the format of the data sent from the server.
hconv
Handle to the conversation.
hsz1
Handle to the topic name.
hsz2
Handle to the item name.
hdata
Handle to the data that the client is sending to the server.
dwData1
Not used.
dwData2
Not used.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeClientTransaction, DdeInitialize


XTYP_REGISTER

A DDE callback function, DdeCallback, receives the XTYP_REGISTER transaction type whenever a 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.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_REGISTER
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Not used.
hconv
Not used.
hsz1
Handle to the base service name being registered.
hsz2
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeInitialize, DdeNameService


XTYP_REQUEST

A client uses the XTYP_REQUEST transaction to request data from a server. A DDE server callback function, DdeCallback, receives this transaction when a client specifies XTYP_REQUEST in the DdeClientTransaction function.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_REQUEST
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Specifies the format in which the server should submit data to the client.
hconv
Handle to the conversation.
hsz1
Handle to the topic name.
hsz2
Handle to the item name.
hdata
Not used.
dwData1
Not used.
dwData2
Not used.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeClientTransaction, DdeCreateDataHandle, DdeEnableCallback, DdeInitialize


XTYP_UNREGISTER

A DDE callback function, DdeCallback, receives the XTYP_UNREGISTER transaction whenever a 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.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_UNREGISTER
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Not used.
hconv
Not used.
hsz1
Handle to the base service name being unregistered.
hsz2
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeInitialize, DdeNameService


XTYP_WILDCONNECT

The XTYP_WILDCONNECT 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. A DDE server callback function, DdeCallback, receives this transaction when a client specifies a NULL service name, a NULL topic name, or both in a call to the DdeConnect or DdeConnectList function.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_WILDCONNECT
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
uFmt
Not used.
hconv
Not used.
hsz1
Handle to the topic name. If this parameter is NULL, the client is requesting a conversation on all topic names that the server supports.
hsz2
Handle to 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
Pointer 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 Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, CONVCONTEXT, DdeConnect, DdeInitialize, HSZPAIR


XTYP_XACT_COMPLETE

A DDE client callback function, DdeCallback, receives the XTYP_XACT_COMPLETE transaction when an asynchronous transaction, initiated by a call to the DdeClientTransaction function, has completed.

HDDEDATA CALLBACK DdeCallback(
  UINT uType,     // XTYP_XACT_COMPLETE
  UINT uFmt,      // clipboard data format
  HCONV hconv,    // handle to the conversation
  HSZ hsz1,       // handle to a string
  HSZ hsz2,       // handle to a string
  HDDEDATA hdata, // handle to a global memory object
  DWORD dwData1,  // transaction-specific data
  DWORD dwData2   // transaction-specific data
);

Parameters

uType
Specifies the transaction type.
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
Handle to the conversation.
hsz1
Handle to the topic name involved in the completed transaction.
hsz2
Handle to the item name involved in the completed transaction.
hdata
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Ddeml.h; include Windows.h.

See Also

Dynamic Data Exchange Management Library Overview, Dynamic Data Exchange Management Transactions, DdeClientTransaction, DdeGetData


Handles and Objects

An object is a data structure that represents a system resource, such as a file, thread, or graphic image. An application cannot directly access object data or the system resource that an object represents. Instead, an application must obtain an object handle, which it can use to examine or modify the system resource. Each handle has an entry in an internally maintained table. These entries contain the addresses of the resources and the means to identify the resource type.

  • About Handles and Objects
  • Object Categories
  • Handle and Object Reference


About Handles and Objects

The system uses objects and handles to regulate access to system resources for two main reasons. First, the use of objects ensures that Microsoft can update system functionality, as long as the original object interface is maintained. When subsequent versions of the system are released, you can use the updated object with little or no additional work.

Secondly, the use of objects enables you to take advantage of Microsoft® Windows NT®/Windows® 2000 security. Each object has its own access-control list (ACL) that specifies the actions a process can perform on the object. Windows NT/Windows 2000 examines an object's ACL each time an application creates a handle to the object. For more information, see Access Control.

  • Object Manager
  • Object Interface
  • Handle Limitations
  • Handle Inheritance


Object Manager

An object consists of a standard header and object-specific attributes. Because all objects have the same structure, there is a single object manager that maintains all objects.

The object header includes items such as the object name, so that other processes can reference the object by name, and a security descriptor, so that the object manager can control which processes access the system resource.

The tasks that the object manager performs include the following:

  • Creating objects
  • Verifying that that a process has the right to use the object
  • Creating object handles and returning them to the caller
  • Maintaining resource quotas
  • Creating duplicate handles
  • Closing handles to objects


Object Interface

The Microsoft® Win32® application programming interface (API) provides functions that perform the following tasks:

  • Create an object
  • Get an object handle
  • Get information about the object
  • Set information about the object
  • Close the object handle
  • Destroy the object

Some of these tasks are not necessary for each object. Some of these tasks are combined for certain objects. For example, an application can create an event object. Other applications can open the event to obtain a unique handle to this event object. As each application finishes using the event, it closes its handle to the object. When there are no remaining open handles to the event object, the system destroys the event object. In contrast, an application can obtain a handle to an existing window object. When the window object is no longer needed, the application must destroy the object, which invalidates the window handle.

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.

Handles and objects consume memory. Therefore, to preserve system performance, you should close handles and delete objects as soon as they are no longer needed. If you do not do this, your application can hurt system performance, due to excessive use of the paging file.

Note 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; these objects are destroyed when the creating thread terminates.


Handle Limitations

Some 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 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 system is limited only by the amount of memory available. However, a single process can have no more than 65,536 handles. Some object types support a limited number of handles per process, while other object types support a limited number of handles in the system.


Handle Inheritance

A child process can inherit handles from its parent process. An inherited handle is valid only in the context of the child process. To enable a child process to inherit open handles from its parent process, use the following steps.

  1. Create the handle with the bInheritHandle member of the SECURITY_ATTRIBUTES structure set to TRUE.
  2. Create the child process using the CreateProcess function, with the bInheritHandles parameter set to TRUE.

The DuplicateHandle function duplicates a handle to be used in the current process or in another process. If an application duplicates one of its handles for 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. Processes can inherit or duplicate handles to the following types of objects:

  • Access Token
  • Communications device
  • Console input
  • Console screen buffer
  • Desktop
  • Directory
  • Event
  • File
  • File mapping
  • Job
  • Mailslot
  • Mutex
  • Pipe
  • Process
  • Registry key
  • Semaphore
  • Socket
  • Thread
  • Timer
  • Window station

All other objects are private to the process that created them; their object handles cannot be duplicated or inherited.

For more information, see Inheritance.


Object Categories

The system provides three categories of objects: user, graphics device interface (GDI), and kernel. 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.

User object | Overview
Accelerator table | Keyboard Accelerators
Caret | Carets
Cursor | Cursors
DDE conversation | Dynamic Data Exchange Management Library
Desktop | Window Stations and Desktops
Hook | Hooks
Icon | Icons
Menu | Menus
Window | Windows
Window position | Windows
Window station | Window Stations and Desktops

GDI object | Overview
Bitmap | Bitmaps
Brush | Brushes
DC | Device Contexts
Enhanced metafile | Metafiles
Enhanced-metafile DC | Metafiles
Font | Fonts and Text
Memory DC | Device Contexts
Metafile | Metafiles
Metafile DC | Metafiles
Palette | Colors
Pen and extended pen | Pens
Region | Regions

Kernel object | Overview
Access token | Access Control
Change notification | File I/O
Communications device | Communications
Console input | Consoles and Character-Mode Support
Console screen buffer | Consoles and Character-Mode Support
Event | Synchronization
Event log | Event Logging
File | File I/O
File mapping | File Mapping
Find file | File I/O
Heap | Memory Management
Job | Job Objects
Mailslot | Mailslots
Module | Dynamic-Link Libraries
Mutex | Synchronization
Pipe | Pipes
Process | Processes and Threads
Semaphore | Synchronization
Socket | Windows Sockets 2
Thread | Processes and Threads
Timer | Synchronization
Update resource | Resources


User Objects

User objects support only one handle per object. Processes cannot inherit or duplicate handles to user objects. There is no per-process limit on user handles, but there is a system-wide limit of 65,536 user handles.

Handles to user objects are public to all processes. That is, any process can use the user object handle, provided that the process has security access to the object.

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 user objects, along with each object's creator and destroyer functions. The creator functions either create the object and an object handle or simply return the existing object handle. The destroyer functions remove the object from memory, which invalidates the object handle.

User Objects

Object | Creator function | Destroyer function
Accelerator table | CreateAcceleratorTable | DestroyAcceleratorTable
Caret | CreateCaret | DestroyCaret
Cursor | CreateCursor, LoadCursor, LoadImage | DestroyCursor
DDE conversation | DdeConnect, DdeConnectList | DdeDisconnect, DdeDisconnectList
Desktop | GetThreadDesktop | Applications cannot delete this object.
Hook | SetWindowsHookEx | UnhookWindowsHookEx
Icon | CreateIconIndirect, LoadIcon, LoadImage | DestroyIcon
Menu | CreateMenu, CreatePopupMenu, LoadMenu, LoadMenuIndirect | DestroyMenu
Window | CreateWindow, CreateWindowEx, CreateDialogParam, CreateDialogIndirectParam, CreateMDIWindow | DestroyWindow
Window position | BeginDeferWindowPos | EndDeferWindowPos
Window station | GetProcessWindowStation | Applications cannot delete this object.


GDI Objects

GDI objects support only one handle per object. Handles to GDI objects are private to a process. That is, only the process that created the GDI object can use the object handle. A single process may have no more than 16,384 open GDI object handles.

The following table lists the GDI objects, along with each object's creator and destroyer functions. The creator functions either create the object and an object handle or simply return the existing object handle. The destroyer functions remove the object from memory, which invalidates the object handle.

GDI Objects

Object | Creator function | Destroyer function
Bitmap | CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDIBSection, CreateDiscardableBitmap | DeleteObject
Brush | CreateBrushIndirect, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush | DeleteObject
DC | CreateDC | DeleteDC, ReleaseDC
Enhanced metafile | CreateEnhMetaFile | DeleteEnhMetaFile
Enhanced-metafile DC | CreateEnhMetaFile | CloseEnhMetaFile
Font | CreateFont, CreateFontIndirect | DeleteObject
Memory DC | CreateCompatibleDC | DeleteDC
Metafile | CreateMetaFile | DeleteMetaFile
Metafile DC | CreateMetaFile | CloseMetaFile
Palette | CreatePalette | DeleteObject
Pen and extended pen | CreatePen, CreatePenIndirect, ExtCreatePen | DeleteObject
Region | CombineRgn, CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreatePolyPolygonRgn, CreateRectRgn, CreateRectRgnIndirect, CreateRoundRectRgn, ExtCreateRegion, PathToRegion | DeleteObject


Kernel Objects

Kernel object handles are process specific. That is, a process must either create the object or open an existing object to obtain a kernel object handle. The per-process limit on kernel handles is 2^30.

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 security access to the object. Kernel object handles include access rights that indicate the actions that can be granted or denied to a process. 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, see Securable 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. The creating application could also duplicate one of its handles into the same process or into another process by using the DuplicateHandle function.

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.

The system 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 kernel objects, along with each object's creator and destroyer functions. The creator functions either create the object and an object handle or create a new existing object handle. The destroyer 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 | Destroyer function
Access token | CreateRestrictedToken, DuplicateToken, DuplicateTokenEx, OpenProcessToken, OpenThreadToken | CloseHandle
Change notification | FindFirstChangeNotification | FindCloseChangeNotification
Communications device | CreateFile | CloseHandle
Console input | CreateFile, with CONIN$ | CloseHandle
Console screen buffer | CreateFile, with CONOUT$ | CloseHandle
Event | CreateEvent, OpenEvent | CloseHandle
Event log | OpenEventLog, RegisterEventSource, OpenBackupEventLog | CloseEventLog
File | CreateFile | CloseHandle , DeleteFile
File mapping | CreateFileMapping, OpenFileMapping | CloseHandle
Find file | FindFirstFile | FindClose
Heap | HeapCreate | HeapDestroy
Job | CreateJobObject | CloseHandle
Mailslot | CreateMailslot | CloseHandle
Module | LoadLibrary, GetModuleHandle | FreeLibrary
Mutex | CreateMutex, OpenMutex | CloseHandle
Pipe | CreateNamedPipe, CreatePipe | CloseHandle, DisconnectNamedPipe
Process | CreateProcess, OpenProcess, GetCurrentProcess | CloseHandle, TerminateProcess
Semaphore | CreateSemaphore , OpenSemaphore | CloseHandle
Socket | socket, accept | CloseHandle
Thread | CreateThread, CreateRemoteThread, GetCurrentThread | CloseHandle, TerminateThread
Timer | CreateWaitableTimer , OpenWaitableTimer | CloseHandle
Update resource | BeginUpdateResource | EndUpdateResource


Handle and Object Reference

The following elements are used with handles and objects.

  • Handle and Object Functions


Handle and Object Functions

The following functions are used with handles and objects.

Function | Description
CloseHandle | Closes an open object handle.
DuplicateHandle | Duplicates an object handle.
GetHandleInformation | Retrieves certain properties of an object handle.
SetHandleInformation | Sets certain properties of an object handle.


CloseHandle

The CloseHandle function closes an open object handle.

BOOL CloseHandle(
  HANDLE hObject   // handle to object
);

Parameters

hObject
[in/out] Handle to an open object.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Windows NT/2000: Closing an invalid handle raises an exception when the application is running under a debugger. This includes closing a handle twice, and using CloseHandle on a handle returned by the FindFirstFile function.

Remarks

The CloseHandle function closes handles to the following objects:

  • Access token
  • Communications device
  • Console input
  • Console screen buffer
  • Event
  • File
  • File mapping
  • Job
  • Mailslot
  • Mutex
  • Named pipe
  • Process
  • Semaphore
  • Socket
  • Thread

CloseHandle invalidates the specified object handle, decrements the object's handle count, and performs object retention checks. After the last handle to an object is closed, the object is removed from the system.

Closing a thread handle does not terminate the associated thread. To remove a thread object, you must terminate the thread, then close all handles to the thread.

Use CloseHandle to close handles returned by calls to the CreateFile function. Use FindClose to close handles returned by calls to FindFirstFile.

MAPI: For more information, see Syntax and Limitations for Win32 Functions Useful in MAPI Development.

For an example, see Cleaning up.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Handles and Objects Overview, Handle and Object Functions, CreateFile, DeleteFile, FindClose, FindFirstFile


DuplicateHandle

The DuplicateHandle function duplicates an object handle. The duplicate handle refers to the same object as the original handle. Therefore, any changes to the object are reflected through both handles. For example, the current file mark for a file handle is always the same for both handles.

BOOL DuplicateHandle(
  HANDLE hSourceProcessHandle,  // handle to source process
  HANDLE hSourceHandle,         // handle to duplicate
  HANDLE hTargetProcessHandle,  // handle to target process
  LPHANDLE lpTargetHandle,      // duplicate handle
  DWORD dwDesiredAccess,        // requested access
  BOOL bInheritHandle,          // handle inheritance option
  DWORD dwOptions               // optional actions
);

Parameters

hSourceProcessHandle
[in] Handle to the process with the handle to duplicate.

Windows NT/2000: The handle must have PROCESS_DUP_HANDLE access. For more information, see Process Security and Access Rights.

hSourceHandle
[in] 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
[in] Handle to the process that is to receive the duplicated handle. The handle must have PROCESS_DUP_HANDLE access.
lpTargetHandle
[out] Pointer to a variable that receives 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. This behavior exists only for backward compatibility with previous versions of this function. You should not use this feature, as you will lose system resources until the target process terminates.

dwDesiredAccess
[in] 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
[in] 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
[in] Specifies optional actions. This parameter can be zero, or any combination of the following values.
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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

DuplicateHandle can duplicate handles to the following types of objects.

Object | Description
Access token | The handle is returned by the CreateRestrictedToken, DuplicateToken, DuplicateTokenEx, OpenProcessToken, or OpenThreadToken function.
Communications device | The handle is returned by the CreateFile function.
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.
Desktop | The handle is returned by the GetThreadDesktop function.
Directory | The handle is returned by the CreateDirectory function.
Event | The handle is returned by the CreateEvent or OpenEvent function.
File | The handle is returned by the CreateFile function.
File mapping | The handle is returned by the CreateFileMapping function.
Job | The handle is returned by the CreateJobObject function.
Mailslot | The handle is returned by the CreateMailslot 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, GetCurrentProcess, or OpenProcess function.
Registry key | Windows NT/2000: 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. Windows 95/98: You cannot use DuplicateHandle to duplicate registry key handles.
Semaphore | The handle is returned by the CreateSemaphore or OpenSemaphore function.
Socket | The handle is returned by the socket or accept function.
Thread | The handle is returned by the CreateProcess, CreateThread, CreateRemoteThread, or GetCurrentThread function
Timer | The handle is returned by the CreateWaitableTimer or OpenWaitableTimer function.
Window station | The handle is returned by the GetProcessWindowStation function.

Note that DuplicateHandle should not be used to duplicate handles to I/O completion ports. In this case, no error is returned, but the duplicate handle cannot be used.

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 flags is valid for mutex objects.

Access | Description
MUTEX_ALL_ACCESS | Specifies all possible access flags for the mutex object.
SYNCHRONIZE | Windows NT/2000: 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/2000: 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/2000: 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/2000: 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/2000: 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.

For an example, see Creating a Child Process with Redirected Input and Output.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Handles and Objects Overview, Handle and Object Functions, CloseHandle


GetHandleInformation

The GetHandleInformation function retrieves certain properties of an object handle.

BOOL GetHandleInformation(
  HANDLE hObject,    // handle to object
  LPDWORD lpdwFlags  // handle properties
);

Parameters

hObject
[in] Specifies a handle to an object. The GetHandleInformation function obtains information about this object handle.

You can specify a handle to one of the following types of objects: access token, event, file, file mapping, job, mailslot, mutex, pipe, printer, process, registry key, semaphore, serial communication device, socket, thread, or waitable timer.

Windows 2000: This parameter can also be a handle to a console input buffer or a console screen buffer.

lpdwFlags
[out] Pointer to a variable that receives 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Handles and Objects Overview, Handle and Object Functions, CloseHandle, CreateProcess, SetHandleInformation


SetHandleInformation

The SetHandleInformation function sets certain properties of an object handle. The information is specified as a set of bit flags.

BOOL SetHandleInformation(
  HANDLE hObject,  // handle to object
  DWORD dwMask,    // flags to change
  DWORD dwFlags    // new values for flags
);

Parameters

hObject
[in] Handle to an object. The SetHandleInformation function sets information associated with this object handle.

You can specify a handle to one of the following types of objects: access token, event, file, file mapping, job, mailslot, mutex, pipe, printer, process, registry key, semaphore, serial communication device, socket, thread, or waitable timer.

Windows 2000: This parameter can also be a handle to a console input buffer or a console screen buffer.

dwMask
[in] A mask that specifies the bit flags to be changed. Use the same flag constants shown in the description of dwFlags.
dwFlags
[in] A set of bit flags that specify properties of the object handle. This parameter can be one of the following values.
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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

To set or clear the associated bit flag in dwFlags, you must set a change mask bit flag in dwMask.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Handles and Objects Overview, Handle and Object Functions, CreateProcess, CloseHandle, GetHandleInformation


Hooks

A hook is a point in the system 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 hooks and explains how to use them in a Win32®-based application.

  • About Hooks
  • Using Hooks
  • Hook Reference

For more information, see WinEvents.


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.

The following topics describe hooks.

  • Hook Chains
  • Hook Procedures
  • Hook Types


Hook Chains

The system supports many different types of hooks; each type provides access to a different aspect of its message-handling mechanism. For example, an application can use the WH_MOUSE hook to monitor the message traffic for mouse messages.

The system 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, the system 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(
  int nCode,
  WPARAM wParam,
  LPARAM lParam
);

HookProc is a placeholder for an application-defined name.

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.

The SetWindowsHookEx function 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, the system 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. the system passes messages to each hook procedure, regardless of whether a particular procedure calls CallNextHookEx.

A global hook monitors messages for all threads in the same desktop as the calling thread. A thread-specific hook monitors messages for only an individual thread. A global hook procedure can be called in the context of any application in the same desktop as the calling thread, 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, 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 system's message-handling mechanism. The following sections describe the available hooks.

  • WH_CALLWNDPROC and WH_CALLWNDPROCRET Hooks
  • WH_CBT Hook
  • WH_DEBUG Hook
  • WH_FOREGROUNDIDLE Hook
  • WH_GETMESSAGE Hook
  • WH_JOURNALPLAYBACK Hook
  • WH_JOURNALRECORD Hook
  • WH_KEYBOARD Hook
  • WH_KEYBOARD_LL Hook
  • WH_MOUSE Hook
  • WH_MOUSE_LL Hook
  • WH_MSGFILTER and WH_SYSMSGFILTER Hooks
  • WH_SHELL Hook


WH_CALLWNDPROC and WH_CALLWNDPROCRET Hooks

The WH_CALLWNDPROC and WH_CALLWNDPROCRET hooks enable you to monitor messages sent to window procedures. The system 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 a pointer to 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. Subclassing the window does not work for messages set between processes.

For more information, see the CallWndProc and CallWndRetProc functions.


WH_CBT Hook

The system 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 the system allows or prevents one of these operations. The WH_CBT hook is intended primarily for computer-based training (CBT) applications.

For more information, see the CBTProc function.

For information, see WinEvents.


WH_DEBUG Hook

The system calls a WH_DEBUG hook procedure before calling hook procedures associated with any other hook in the system. You can use this hook to determine whether to allow the system to call hook procedures associated with other types of hooks.

For more information, see the DebugProc function.


WH_FOREGROUNDIDLE Hook

The WH_FOREGROUNDIDLE hook enables you to perform low priority tasks during times when its foreground thread is idle. The system calls a WH_FOREGROUNDIDLE hook procedure when the application's foreground thread is about to become idle.

For more information, see the ForegroundIdleProc function.


WH_GETMESSAGE Hook

The WH_GETMESSAGE hook enables an application to monitor messages about to be returned by the GetMessage or PeekMessage function. You can use the WH_GETMESSAGE hook to monitor mouse and keyboard input and other messages posted to the message queue.

For more information, see the GetMsgProc function.


WH_JOURNALPLAYBACK Hook

The WH_JOURNALPLAYBACK hook enables an application to insert messages into the system message queue. You can 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.

For more information, see the JournalPlaybackProc function.


WH_JOURNALRECORD Hook

The WH_JOURNALRECORD hook enables you to monitor and record input events. Typically, you use this hook to record a sequence of mouse and keyboard events to 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.

For more information, see the JournalRecordProc function.


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. You can use the WH_KEYBOARD hook to monitor keyboard input posted to a message queue.

For more information, see the KeyboardProc function.


WH_KEYBOARD_LL Hook

The WH_KEYBOARD_LL hook enables you to monitor keyboard input events about to be posted in a thread input queue.

For more information, see the LowLevelKeyboardProc function.


WH_MOUSE Hook

The WH_MOUSE hook enables you to monitor mouse messages about to be returned by the GetMessage or PeekMessage function. You can use the WH_MOUSE hook to monitor mouse input posted to a message queue.

For more information, see the MouseProc function.


WH_MOUSE_LL Hook

The WH_MOUSE_LL hook enables you to monitor mouse input events about to be posted in a thread input queue.

For more information, see the LowLevelMouseProc function.


WH_MSGFILTER and WH_SYSMSGFILTER Hooks

The WH_MSGFILTER and WH_SYSMSGFILTER hooks enable you 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 only monitor 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 you 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.

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, encapsulate the filtering operations in a WH_MSGFILTER hook procedure and call 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; you 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.

For more information, see the MessageProc and SysMsgProc functions.


WH_SHELL Hook

A shell application can use the WH_SHELL hook to receive important notifications. The system 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.

Note that custom shell applications do not receive WH_SHELL messages. Therefore, any application that registers itself as the default shell must call the SystemParametersInfo function with SPI_SETMINIMIZEDMETRICS before it (or any other application) can receive WH_SHELL messages.

For more information, see the ShellProc function.


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 in the same desktop as the calling thread or with a particular thread, and a pointer to the 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 to the DLL module before it can install the hook procedure. To retrieve a handle to the DLL module, call the LoadLibrary function with the name of the DLL. After you have obtained the handle, you can call the GetProcAddress function to retrieve a pointer to the hook procedure. Finally, 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 same desktop as the calling thread. 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 to 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 application in the desktop, 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. The system 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 to 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 following example 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

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];

LRESULT WINAPI MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam,
    LPARAM 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 WINAPI CallWndProc(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(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(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(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(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(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(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;

        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 elements are associated with hooks.

  • Hook Functions
  • Hook Structures
  • Hook Messages


Hook Functions

The following functions are used with hooks.

Function | Description
CallMsgFilter | Passes the specified message and hook code to the hook procedures associated with the WH_SYSMSGFILTER and WH_SYSMSGFILTER hooks.
CallNextHookEx | Passes the hook information to the next hook procedure in the current hook chain.
CallWndProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
CallWndRetProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
CBTProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
DebugProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
ForegroundIdleProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
GetMsgProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
JournalPlaybackProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
JournalRecordProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
KeyboardProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
LowLevelKeyboardProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
LowLevelMouseProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
MessageProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
MouseProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
SetWindowsHookEx | Installs an application-defined hook procedure into a hook chain.
ShellProc | An application-defined or library-defined callback function used with the SetWindowsHookEx function.
SysMsgProc | A library-defined callback function used with the SetWindowsHookEx function.
UnhookWindowsHookEx | Removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.


CallMsgFilter

The CallMsgFilter function passes the specified message and hook code to the hook procedures associated with the WH_SYSMSGFILTER and WH_MSGFILTER hooks. 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,  // message data
  int nCode     // hook code
);

Parameters

lpMsg
[in] Pointer to an MSG structure that contains the message to be passed to the hook procedures.
nCode
[in] 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 Values

If the application should process the message further, the return value is zero.

If the application should not process the message further, the return value is nonzero.

Remarks

The system 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.

Install this hook procedure by using the SetWindowsHookEx function.

For an example, see WH_MSGFILTER and WH_SYSMSGFILTER Hooks.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Hooks Overview, Hook Functions, MessageProc, MSG, SetWindowsHookEx, SysMsgProc


CallNextHookEx

The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain. A hook procedure can call this function either before or after processing the hook information.

LRESULT CallNextHookEx(
  HHOOK hhk,      // handle to 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
[in] Handle to the current hook. An application receives this handle as a result of a previous call to the SetWindowsHookEx function.
nCode
[in] 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
[in] 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
[in] 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 Values

This value is 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, but it is highly recommended; otherwise, other applications that have installed hooks will not receive hook notifications and may behave incorrectly as a result. You should call CallNextHookEx unless you absolutely need to prevent the notification from being seen by other applications.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Hooks Overview, Hook Functions, SetWindowsHookEx, UnhookWindowsHookEx


CallWndProc

The CallWndProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function.

  • Windows 95/98 and Windows NT 3.51: The system calls this function whenever the thread calls the SendMessage function. The WH_CALLWNDPROC hook is called in the context of the thread that calls SendMessage, not the thread that receives the message.
  • Windows NT 4.0 and later: The system calls this function before calling the window procedure to process a message sent to the thread.

The HOOKPROC type defines a pointer to this callback function. CallWndProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK CallWndProc(
  int nCode,      // hook code
  WPARAM wParam,  // current-process flag
  LPARAM lParam   // message data
);

Parameters

nCode
[in] 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 must return the value returned by CallNextHookEx.
wParam
[in] Specifies whether the message was sent by the current thread. If the message was sent by the current thread, it is nonzero; otherwise, it is zero.
lParam
[in] Pointer to a CWPSTRUCT structure that contains details about the message.

Return Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure does not call CallNextHookEx, 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 a pointer to the hook procedure in a call to the SetWindowsHookEx function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, CWPSTRUCT, SendMessage, SetWindowsHookEx


CallWndRetProc

The CallWndRetProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function after the SendMessage function is called. The hook procedure can examine the message; it cannot modify it.

The HOOKPROC type defines a pointer to this callback function. CallWndRetProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK CallWndRetProc(
  int nCode,     // hook code
  WPARAM wParam, // current-process flag
  LPARAM lParam  // message data
);

Parameters

nCode
[in] 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
[in] 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
[in] Pointer to a CWPRETSTRUCT structure that contains details about the message.

Return Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROCRET hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure does not call CallNextHookEx, the return value should be zero.

Remarks

An application installs the hook procedure by specifying the WH_CALLWNDPROCRET hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, CallWndProc, CWPRETSTRUCT, SendMessage, SetWindowsHookEx


CBTProc

The CBTProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function 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. A computer-based training (CBT) application uses this hook procedure to receive useful notifications from the system.

The HOOKPROC type defines a pointer to this callback function. CBTProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK CBTProc(
  int nCode,      // hook code
  WPARAM wParam,  // depends on hook code
  LPARAM lParam   // depends on hook code
);

Parameters

nCode
[in] 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 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
[in] Depends on the nCode parameter. For details, see the following Remarks section.
lParam
[in] Depends on the nCode parameter. For details, see the following Remarks section.

Return Values

The value returned by the hook procedure determines whether the system allows or prevents one of these operations. 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 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 a pointer to 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 to the window about to be activated. | Specifies a long pointer to a CBTACTIVATESTRUCT structure containing the handle to the active window and specifies whether the activation is changing because of a mouse click.
HCBT_CLICKSKIPPED | Specifies 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 to 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 to 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 to the window about to be destroyed. | Is undefined and must be set to zero.
HCBT_KEYSKIPPED | Specifies 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 WM_KEYUP or WM_KEYDOWN.
HCBT_MINMAX | Specifies the handle to 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 to 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 to the window gaining the keyboard focus. | Specifies the handle to 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.

For information, see WinEvents.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, CreateWindow, SetWindowsHookEx, WM_SYSCOMMAND


DebugProc

The DebugProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function before calling the hook procedures associated with any 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.

The HOOKPROC type defines a pointer to this callback function. DebugProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK DebugProc(
  int nCode,      // hook code
  WPARAM wParam,  // hook type
  LPARAM lParam   // debugging information
);

Parameters

nCode
[in] 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
[in] 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 | 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 and the WH_SHELL Hook section.
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
[in] Pointer to a DEBUGHOOKINFO structure that contains the parameters to be passed to the destination hook procedure.

Return Values

To prevent the system from calling the hook, the hook procedure must return a nonzero value. Otherwise, the hook procedure must call CallNextHookEx.

Remarks

An application installs this hook procedure by specifying the WH_DEBUG hook type and the pointer to the hook procedure in a call to the SetWindowsHookEx function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, CallWndProc, CallWndRetProc, CBTProc, DEBUGHOOKINFO, GetMsgProc, JournalPlaybackProc, JournalRecordProc, KeyboardProc, MessageProc, MouseProc, SetWindowsHookEx, ShellProc, SysMsgProc


ForegroundIdleProc

The ForegroundIdleProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function whenever the foreground thread is about to become idle.

The HOOKPROC type defines a pointer to this callback function. ForegroundIdleProc is a placeholder for the application-defined or library-defined function name.

DWORD CALLBACK ForegroundIdleProc(
  int code,      // hook code
  DWORD wParam,  // not used
  LONG lParam    // not used
);

Parameters

code
[in] 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
This parameter is not used.
lParam
This parameter is not used.

Return Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_FOREGROUNDIDLE hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure does not call CallNextHookEx, the return value should be zero.

Remarks

An application installs this hook procedure by specifying the WH_FOREGROUNDIDLE hook type and the pointer to the hook procedure in a call to the SetWindowsHookEx function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, SetWindowsHookEx


GetMsgProc

The GetMsgProc function is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function whenever the GetMessage or PeekMessage function has retrieved a message from an application message queue. Before returning the retrieved message to the caller, the system passes the message to the hook procedure.

The HOOKPROC type defines a pointer to this callback function. GetMsgProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK GetMsgProc(
  int code,       // hook code
  WPARAM wParam,  // removal option
  LPARAM lParam   // message
);

Parameters

code
[in] 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
[in] 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
[in] Pointer to an MSG structure that contains details about the message.

Return Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_GETMESSAGE hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure does not call CallNextHookEx, 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 or PeekMessage 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 a pointer to the hook procedure in a call to the SetWindowsHookEx function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, GetMessage, MSG, PeekMessage, SetWindowsHookEx


JournalPlaybackProc

The JournalPlaybackProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. Typically, an application uses this function 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.

The HOOKPROC type defines a pointer to this callback function. JournalPlaybackProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK JournalPlaybackProc(
  int code,       // hook code
  WPARAM wParam,  // not used
  LPARAM lParam   // message being processed
);

Parameters

code
[in] 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
This parameter is not used.
lParam
[in] Pointer 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 Values

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.

Install the JournalPlaybackProc hook procedure by specifying the WH_JOURNALPLAYBACK hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.

If the user presses CTRL+ESC 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 repeat count. The event is always taken to represent one key event.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, EVENTMSG, JournalRecordProc, PeekMessage, SetWindowsHookEx, WM_CANCELJOURNAL


JournalRecordProc

The JournalRecordProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The function records messages the system removes from the system message queue. Later, an application can use a JournalPlaybackProc hook procedure to play back the messages.

The HOOKPROC type defines a pointer to this callback function. JournalRecordProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK JournalRecordProc(
  int code,       // hook code
  WPARAM wParam,  // not used
  LPARAM lParam   // message being processed
);

Parameters

code
[in] Specifies how to process the message. This parameter can be one of the following values.
Value | Meaning
HC_ACTION | The lParam parameter is a pointer 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
This parameter is not used.
lParam
[in] Pointer to an EVENTMSG structure that contains the message to be recorded.

Return Values

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.

Install the JournalRecordProc hook procedure by specifying the WH_JOURNALRECORD hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.

A JournalRecordProc hook procedure does not need to live in a dynamic-link library. A 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 two other key combinations that cannot be recorded: CTRL+ESC and CTRL+ALT+DEL. Those two 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, EVENTMSG, JournalPlaybackProc, SetWindowsHookEx, WM_CANCELJOURNAL


KeyboardProc

The KeyboardProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function whenever an application calls the GetMessage or PeekMessage function and there is a keyboard message (WM_KEYUP or WM_KEYDOWN) to be processed.

The HOOKPROC type defines a pointer to this callback function. KeyboardProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK KeyboardProc(
  int code,       // hook code
  WPARAM wParam,  // virtual-key code
  LPARAM lParam   // keystroke-message information
);

Parameters

code
[in] 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
[in] Specifies the virtual-key code of the key that generated the keystroke message.
lParam
[in] Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag. This parameter can be one or more 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 Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_KEYBOARD hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure.

Remarks

An application installs the hook procedure by specifying the WH_KEYBOARD hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, GetMessage, PeekMessage, SetWindowsHookEx, WM_KEYUP, WM_KEYDOWN


LowLevelKeyboardProc

The LowLevelKeyboardProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function every time a new keyboard input event is about to be posted into a thread input queue. The keyboard input can come from the local keyboard driver or from calls to the keybd_event function. If the input comes from a call to keybd_event, the input was "injected".

The HOOKPROC type defines a pointer to this callback function. LowLevelKeyboardProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK LowLevelKeyboardProc(
  int nCode,     // hook code
  WPARAM wParam, // message identifier
  LPARAM lParam  // message data
);

Parameters

nCode
[in] 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 keyboard 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
[in] Specifies the identifier of the keyboard message. This parameter can be one of the following messages: WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP.
lParam
[in] Pointer to a KBDLLHOOKSTRUCT structure.

Return Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_KEYBOARD_LL hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure.

Remarks

An application installs the hook procedure by specifying the WH_KEYBOARD_LL hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.

This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.

The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registry key:

HKEY_CURRENT_USER\Control Panel\Desktop

The value is in milliseconds. If the hook procedure does not return during this interval, the system will pass the message to the next hook.

Note that debug hooks cannot track this type of hook.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 SP3 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, KBDLLHOOKSTRUCT, keybd_event, SetWindowsHookEx, WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP


LowLevelMouseProc

The LowLevelMouseProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system call this function every time a new mouse input event is about to be posted into a thread input queue. The mouse input can come from the local mouse driver or from calls to the mouse_event function. If the input comes from a call to mouse_event, the input was "injected".

The HOOKPROC type defines a pointer to this callback function. LowLevelMouseProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK LowLevelMouseProc(
  int nCode,     // hook code
  WPARAM wParam, // message identifier
  LPARAM lParam  // message data
);

Parameters

nCode
[in] 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.

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
[in] Specifies the identifier of the mouse message. This parameter can be one of the following messages: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_RBUTTONDOWN, or WM_RBUTTONUP.
lParam
[in] Pointer to an MSLLHOOKSTRUCT structure.

Return Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_MOUSE_LL hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure.

Remarks

An application installs the hook procedure by specifying the WH_MOUSE_LL hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.

This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.

The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registry key:

HKEY_CURRENT_USER\Control Panel\Desktop

The value is in milliseconds. If the hook procedure does not return during this interval, the system will pass the message to the next hook.

Note that debug hooks can not track this type of hook.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 SP3 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, mouse_event, MSLLHOOKSTRUCT, SetWindowsHookEx, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_RBUTTONDOWN, WM_RBUTTONUP


MessageProc

The MessageProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function 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.

The HOOKPROC type defines a pointer to this callback function. MessageProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK MessageProc(
  int code,       // hook code
  WPARAM wParam,  // not used
  LPARAM lParam   // message data
);

Parameters

code
[in] 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_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
This parameter is not used.
lParam
[in] Pointer to an MSG structure.

Return Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_MSGFILTER hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure.

Remarks

An application installs the hook procedure by specifying the WH_MSGFILTER hook type and a pointer to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, SetWindowsHookEx, MSG


MouseProc

The MouseProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function whenever an application calls the GetMessage or PeekMessage function and there is a mouse message to be processed.

The HOOKPROC type defines a pointer to this callback function. MouseProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK MouseProc(
  int nCode,      // hook code
  WPARAM wParam,  // message identifier
  LPARAM lParam   // mouse coordinates
);

Parameters

nCode
[in] 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
[in] Specifies the identifier of the mouse message.
lParam
[in] Pointer to a MOUSEHOOKSTRUCT structure.

Return Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_MOUSE hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the target window procedure.

Remarks

An application installs the hook procedure by specifying the WH_MOUSE hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.

The hook procedure must not install a JournalPlaybackProc callback function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, GetMessage, JournalPlaybackProc, MOUSEHOOKSTRUCT, PeekMessage, SetWindowsHookEx


SetWindowsHookEx

The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. You would install a hook procedure to monitor the system for certain types of events. These events are associated either with a specific thread or with all threads in the same desktop as the calling thread.

HHOOK SetWindowsHookEx(
  int idHook,        // hook type
  HOOKPROC lpfn,     // hook procedure
  HINSTANCE hMod,    // handle to application instance
  DWORD dwThreadId   // thread identifier
);

Parameters

idHook
[in] 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, see the CallWndProc hook procedure.
WH_CALLWNDPROCRET | 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_FOREGROUNDIDLE | Installs a hook procedure that will be called when the application's foreground thread is about to become idle. This hook is useful for performing low priority tasks during idle time. For more information, see the ForegroundIdleProc 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_KEYBOARD_LL | Windows NT/2000 or later: Installs a hook procedure that monitors low-level keyboard input events. For more information, see the LowLevelKeyboardProc hook procedure.
WH_MOUSE | Installs a hook procedure that monitors mouse messages. For more information, see the MouseProc hook procedure.
WH_MOUSE_LL | Windows NT/2000 or later: Installs a hook procedure that monitors low-level mouse input events. For more information, see the LowLevelMouseProc 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 same desktop as the calling thread. For more information, see the SysMsgProc hook procedure.

lpfn
[in] Pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a dynamic-link library (DLL). Otherwise, lpfn can point to a hook procedure in the code associated with the current process.
hMod
[in] Handle to the DLL containing the hook procedure pointed to by the lpfn 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
[in] 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 running in the same desktop as the calling thread.

Return Values

If the function succeeds, the return value is the handle to the hook procedure.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

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.

Calling the CallNextHookEx function to chain to the next hook procedure is optional, but it is highly recommended; otherwise, other applications that have installed hooks will not receive hook notifications and may behave incorrectly as a result. You should call CallNextHookEx unless you absolutely need to prevent the notification from being seen by other applications.

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 global scope; others can also be set for only a specific thread, as shown in the following table.

Hook | Scope
WH_CALLWNDPROC | Thread or global
WH_CALLWNDPROCRET | Thread or global
WH_CBT | Thread or global
WH_DEBUG | Thread or global
WH_FOREGROUNDIDLE | Thread or global
WH_GETMESSAGE | Thread or global
WH_JOURNALPLAYBACK | Global only
WH_JOURNALRECORD | Global only
WH_KEYBOARD | Thread or global
WH_KEYBOARD_LL | Global only
WH_MOUSE | Thread or global
WH_MOUSE_LL | Global only
WH_MSGFILTER | Thread or global
WH_SHELL | Thread or global
WH_SYSMSGFILTER | Global only

For a specified hook type, thread hooks are called first, then global hooks.

The global hooks are a shared resource, and installing one affects all applications in the same desktop as the calling thread. All global hook functions must be in libraries. Global 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 its hook procedure.

For an example, see Installing and Releasing Hook Procedures.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, CallWndProc, CallWndRetProc, CBTProc, DebugProc, ForegroundIdleProc, GetMsgProc, JournalPlaybackProc, JournalRecordProc, LowLevelKeyboardProc, LowLevelMouseProc KeyboardProc, MouseProc, MessageProc, ShellProc, SysMsgProc, UnhookWindowsHookEx


ShellProc

The ShellProc hook procedure is an application-defined or library-defined callback function used with the SetWindowsHookEx function. The function receives notifications of shell events from the system.

The HOOKPROC type defines a pointer to this callback function. ShellProc is a placeholder for the application-defined or library-defined function name.

LRESULT CALLBACK ShellProc(
  int nCode,      // hook code
  WPARAM wParam,  // event-specific information
  LPARAM lParam   // event-specific information
);

Parameters

nCode
[in] Specifies the hook code. This parameter can be one of the following values.
Value | Meaning
HSHELL_ACCESSIBILITYSTATE | Windows 2000 or later: The accessibility state has changed.
HSHELL_ACTIVATESHELLWINDOW | The shell should activate its main window.
HSHELL_APPCOMMAND Windows 2000 or later: The user completed an input event (for example, pressed an application command button on the mouse or an application command key on the keyboard), and the application did not handle the WM_APPCOMMAND message generated by that input.

If the shell procedure handles the WM_COMMAND message, it should not call CallNextHookEx. See the Return Values section for more information.
HSHELL_GETMINRECT | A window is being minimized or maximized. The system needs the coordinates of the minimized rectangle for the window.
HSHELL_LANGUAGE | Keyboard language was changed or a new keyboard layout was loaded.
HSHELL_REDRAW | The title of a window in the task bar has been redrawn.
HSHELL_TASKMAN | The user has selected the task list. A shell application that provides a task list should return TRUE to prevent Windows from starting its task list.
HSHELL_WINDOWACTIVATED | The activation has changed to a different top-level, unowned 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
[in] The value depends on the value of the nCode parameter, as shown in the following table.
nCode | wParam
HSHELL_ACCESSIBILITYSTATE | Indicates which accessibility feature has changed state. This value is one of the following: ACCESS_FILTERKEYS, ACCESS_MOUSEKEYS, or ACCESS_STICKYKEYS.
HSHELL_APPCOMMAND | Windows 2000 or later: Where the WM_APPCOMMAND message was originally sent; for example, the handle to a window. For more information, see cmd parameter in WM_APPCOMMAND.
HSHELL_GETMINRECT | Handle to the minimized or maximized window.
HSHELL_LANGUAGE | Handle to the window.
HSHELL_REDRAW | Handle to the redrawn window.
HSHELL_WINDOWACTIVATED | Handle to the activated window.
HSHELL_WINDOWCREATED | Handle to the created window.
HSHELL_WINDOWDESTROYED | Handle to the destroyed window.

lParam
[in] The value depends on the value of the nCode parameter, as shown in the following table.
nCode | lParam
HSHELL_APPCOMMAND Windows 2000 or later: GET_APPCOMMAND_LPARAM(lParam) is the application command corresponding to the input event.

GET_DEVICE_LPARAM(lParam) indicates what generated the input event; for example, the mouse or keyboard. For more information, see the uDevice parameter description under WM_APPCOMMAND.

GET_FLAGS_LPARAM(lParam) depends on the value of cmd in WM_APPCOMMAND. For example, it might indicate which virtual keys were held down when the WM_APPCOMMAND message was originally sent. For more information, see the dwCmdFlags description parameter under WM_APPCOMMAND.
HSHELL_GETMINRECT | Pointer to a RECT structure.
HSHELL_LANGUAGE | Handle to a keyboard layout.
HSHELL_REDRAW | The value is TRUE if the window is flashing, or FALSE otherwise.
HSHELL_WINDOWACTIVATED | The value is TRUE if the window is in full-screen mode, or FALSE otherwise.

Return Values

The return value should be zero unless the value of nCode is HSHELL_APPCOMMAND and the shell procedure handles the WM_COMMAND message. In this case, the return should be nonzero.

Remarks

Install this hook procedure by specifying the WH_SHELL hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, SendMessage, SetWindowsHookEx, WM_APPCOMMAND


SysMsgProc

The SysMsgProc hook procedure is a library-defined callback function used with the SetWindowsHookEx function. The system calls this function 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 function can monitor messages for any dialog box, message box, menu, or scroll bar in the system.

The HOOKPROC type defines a pointer to this callback function. SysMsgProc is a placeholder for the library-defined function name.

LRESULT CALLBACK SysMsgProc(
  int nCode,      // message flag
  WPARAM wParam,  // not used
  LPARAM lParam   // message data
);

Parameters

nCode
[in] 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.

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
This parameter is not used.
lParam
[in] Pointer to an MSG message structure.

Return Values

If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx.

If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_SYSMSGFILTER hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the target window procedure.

Remarks

An application installs the hook procedure by specifying the WH_SYSMSGFILTER hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Functions, CallNextHookEx, MSG, SetWindowsHookEx


UnhookWindowsHookEx

The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.

BOOL UnhookWindowsHookEx(
  HHOOK hhk   // handle to hook procedure
);

Parameters

hhk
[in] Handle to the hook to be removed. This parameter is a hook handle obtained by a previous call to SetWindowsHookEx.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

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.

For an example, see Monitoring System Events.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Hooks Overview, Hook Functions, SetWindowsHookEx


Hook Structures

The following structures are used with hooks.

CBT_CREATEWND
CBTACTIVATESTRUCT
CWPRETSTRUCT
CWPSTRUCT
DEBUGHOOKINFO
EVENTMSG
KBDLLHOOKSTRUCT
MOUSEHOOKSTRUCT
MSLLHOOKSTRUCT


CBT_CREATEWND

The CBT_CREATEWND structure contains information passed to a WH_CBT hook procedure, CBTProc, before a window is created.

typedef struct tagCBT_CREATEWND {
    LPCREATESTRUCT lpcs;
    HWND           hwndInsertAfter;
} CBT_CREATEWND, *LPCBT_CREATEWND;

Members

lpcs
Pointer to a CREATESTRUCT structure that contains initialization parameters for the window about to be created.
hwndInsertAfter
Handle to the window whose position in the Z order precedes that of the window being created.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Hooks Overview, Hook Structures, CBTProc, CREATESTRUCT, SetWindowsHookEx


CBTACTIVATESTRUCT

The CBTACTIVATESTRUCT structure contains information passed to a WH_CBT hook procedure, CBTProc, before a window is activated.

typedef struct tagCBTACTIVATESTRUCT {
    BOOL fMouse;
    HWND hWndActive;
} CBTACTIVATESTRUCT, *LPCBTACTIVATESTRUCT;

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
Handle to the active window.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Structures, CBTProc, SetWindowsHookEx


CWPRETSTRUCT

The CWPRETSTRUCT structure defines the message parameters passed to a WH_CALLWNDPROCRET hook procedure, CallWndRetProc.

typedef struct tagCWPRETSTRUCT {
    LRESULT lResult;
    LPARAM  lParam;
    WPARAM  wParam;
    UINT    message;
    HWND    hwnd;
} CWPRETSTRUCT, *PCWPRETSTRUCT;

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
Handle to the window that processed the message specified by the message value.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Structures, CallWndRetProc, SetWindowsHookEx


CWPSTRUCT

The CWPSTRUCT structure defines the message parameters passed to a WH_CALLWNDPROC hook procedure, CallWndProc.

typedef struct tagCWPSTRUCT {
    LPARAM  lParam;
    WPARAM  wParam;
    UINT    message;
    HWND    hwnd;
} CWPSTRUCT, *PCWPSTRUCT;

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
Handle to the window to receive the message.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Structures, CallWndProc, SetWindowsHookEx


DEBUGHOOKINFO

The DEBUGHOOKINFO structure contains debugging information passed to a WH_DEBUG hook procedure, DebugProc.

typedef struct tagDEBUGHOOKINFO {
    DWORD  idThread;
    DWORD  idThreadInstaller;
    LPARAM lParam;
    WPARAM wParam;
    int    code;
} DEBUGHOOKINFO, *PDEBUGHOOKINFO;

Members

idThread
Handle to the thread containing the filter function.
idThreadInstaller
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Structures, DebugProc, SetWindowsHookEx


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.

typedef struct tagEVENTMSG {
    UINT  message;
    UINT  paramL;
    UINT  paramH;
    DWORD time;
    HWND  hwnd;
} EVENTMSG, *PEVENTMSG;

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
Handle to the window to which the message was posted.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Structures, JournalPlaybackProc, SetWindowsHookEx


KBDLLHOOKSTRUCT

The KBDLLHOOKSTRUCT structure contains information about a low-level keyboard input event.

typedef struct tagKBDLLHOOKSTRUCT {
    DWORD     vkCode;
    DWORD     scanCode;
    DWORD     flags;
    DWORD     time;
    ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

Members

vkCode
Specifies a virtual-key code. The code must be a value in the range 1 to 254.
scanCode
Specifies a hardware scan code for the key.
flags
Specifies the extended-key flag, event-injected flag, context code, and transition-state flag. This member is specified as follows.
Value | Description
0 | 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.
1-3 | Reserved.
4 | Specifies whether the event was injected. The value is 1 if the event was injected; otherwise, it is 0.
5 | Specifies the context code. The value is 1 if the ALT key is pressed; otherwise, it is 0.
6 | Reserved.
7 | Specifies the transition state. The value is 0 if the key is pressed and 1 if it is being released.

An application can use the following values to test the keystroke flags.
Value | Purpose
LLKHF_EXTENDED | Test the extended-key flag.
LLKHF_INJECTED | Test the event-injected flag.
LLKHF_ALTDOWN | Test the context code.
LLKHF_UP | Test the transition-state flag.

time
Specifies the time stamp for this message.
dwExtraInfo
Specifies extra information associated with the message.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 SP3 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Structures, LowLevelKeyboardProc, SetWindowsHookEx


MOUSEHOOKSTRUCT

The MOUSEHOOKSTRUCT structure contains information about a mouse event passed to a WH_MOUSE hook procedure, MouseProc.

typedef struct tagMOUSEHOOKSTRUCT {
    POINT     pt;
    HWND      hwnd;
    UINT      wHitTestCode;
    ULONG_PTR dwExtraInfo;
} MOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT;

Members

pt
Specifies a POINT structure that contains the x- and y-coordinates of the cursor, in screen coordinates.
hwnd
Handle to 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Structures, MouseProc, POINT, SetWindowsHookEx, WM_NCHITTEST


MOUSEHOOKSTRUCTEX

The MOUSEHOOKSTRUCTEX structure contains information about a mouse event passed to a WH_MOUSE hook procedure, MouseProc.

This is an extension of the MOUSEHOOKSTRUCT structure that includes information about wheel movement or the use of the X button.

 typedef struct tagMOUSEHOOKSTRUCTEX {
    MOUSEHOOKSTRUCT;
    DWORD mouseData;
} MOUSEHOOKSTRUCTEX, *PMOUSEHOOKSTRUCTEX;

Members

MOUSEHOOKSTRUCT
The members of a MOUSEHOOKSTRUCT structure make up the first part of this structure.
mouseData
If the message is WM_MOUSEWHEEL, the HIWORD of this member is the wheel delta. The LOWORD is undefined and reserved. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA, which is 120.

If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, or WM_NCXBUTTONDBLCLK, the HIWORD OF mouseData specifies which X button was pressed or released, and the LOWORD is undefined and reserved. This member can be one or more of the following values.
Value | Meaning
XBUTTON1 | The first X button was pressed or released.
XBUTTON2 | The second X button was pressed or released.

Otherwise, mouseData is not used.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Structures, MouseProc, MOUSEHOOKSTRUCT, WM_MOUSEWHEEL, WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, WM_NCXBUTTONDBLCLK


MSLLHOOKSTRUCT

The MSLLHOOKSTRUCT structure contains information about a low-level keyboard input event.

typedef struct tagMSLLHOOKSTRUCT {
  POINT     pt;
  DWORD     mouseData;
  DWORD     flags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;

Members

pt
Specifies a POINT structure that contains the x- and y-coordinates of the cursor, in screen coordinates.
mouseData
If the message is WM_MOUSEWHEEL, the high-order word of this member is the wheel delta. The low-order word is reserved. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA, which is 120.

If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, and the low-order word is reserved. This value can be one or more of the following values.
Value | Meaning
XBUTTON1 | The first X button was pressed or released.
XBUTTON2 | The second X button was pressed or released.

Otherwise, mouseData is not used.

flags
Specifies the event-injected flag.
Value | Meaning
0 | Specifies whether the event was injected. The value is 1 if the event was injected; otherwise, it is 0.
1-15 | Reserved.

An application can use the following value to test the mouse flags.
Value | Purpose
LLMHF_INJECTED | Test the event-injected flag.

time
Specifies the time stamp for this message.
dwExtraInfo
Specifies extra information associated with the message.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 SP3 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Structures, LowLevelMouseProc, POINT, SetWindowsHookEx, WM_MOUSEWHEEL, WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, WM_NCXBUTTONDBLCLK


Hook Messages

The following messages are used with hooks.

WM_CANCELJOURNAL
WM_QUEUESYNC


WM_CANCELJOURNAL

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 Values

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, the system automatically cancels any journaling activities when a user presses CTRL+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.

The WM_CANCELJOURNAL message has a NULL window handle, therefore 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 (through 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 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 key code (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 or CTRL+ALT+DEL cause the system to cancel journalling regardless of a journalling application's behavior.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Messages, DispatchMessage, GetMessage, JournalPlaybackProc, JournalRecordProc, GetMsgProc, PeekMessage, SetWindowsHookEx


WM_QUEUESYNC

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 Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.

See Also

Hooks Overview, Hook Messages, SetWindowsHookEx


Mailslots

A mailslot is a mechanism for one-way interprocess communications (IPC). A Win32-based application 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
  • Using Mailslots
  • Mailslot Reference

You can 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 multiple processes. One important consideration is that mailslots broadcast messages using datagrams. 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 that can prevent a datagram from reaching a particular destination. Named pipes are like telephone calls: you talk only to one party, but you know that the message is being received. For more information about named pipes, see Pipes.


About Mailslots

A mailslot is a pseudofile; it resides in memory, and you use standard Win32 file functions to access it. The data in a mailslot message can be in any form, but it should be less than 64K. Unlike disk files, however, mailslots are temporary. When all handles to a mailslot are closed, the mailslot and all the data it contains are deleted.

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. 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 any existing 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.

Messages smaller than 425 bytes are sent using datagrams. Messages larger than 426 bytes are sent using a connection-oriented transfer over an SMB session. Connection-oriented transfers are limited to one-to-one communication from one client to one server. Therefore, you lose the ability to broadcast a message from one client to many servers. Note that Windows NT does not support messages that are 425 or 426 bytes.

  • Mailslot Names
  • Server and Client Functions


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. Names are not case sensitive. A mailslot name can be preceded by a path consisting of the names of one or more directories, 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, as shown here:

\\.\mailslot\taxes\bobs_comments
\\.\mailslot\taxes\petes_comments
\\.\mailslot\taxes\sues_comments

To put a message into a mailslot, a process opens a mailslot by name. To write to a mailslot on the local computer, a process can use a mailslot name that has the same form used for creating a mailslot. This situation, however, is relatively uncommon. More frequently, you would use the following form to write to a mailslot on a specific remote computer:

\\ComputerName\mailslot\[path]name

To put a message into every mailslot in the specified domain with a given name, use the following form:

\\DomainName\mailslot\[path]name

To put a message into every mailslot with a given name in the system's primary domain, use the following form:

\\*\mailslot\[path]name


Server and Client Functions

Clients and servers when working with mailslots should use only the functions discussed in the following tables. You should not use other functions, 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, ReadFileEx | 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.
GetHandleInformation | Retrieves properties of the mailslot handle.
SetHandleInformation | Sets properties of the mailslot handle.

Mailslot 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, WriteFileEx | 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 to 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 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 terminating null
    &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;


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.

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.

BOOL WINAPI Readslot(HWND hwnd, HDC hdc)
{
    DWORD cbMessage, cMessage, cbRead;
    BOOL fResult;
    LPSTR lpszBuffer;
    CHAR achID[80];
    DWORD cAllMessages;
    HANDLE hEvent;
    OVERLAPPED ov;

    cbMessage = cMessage = cbRead = 0;

    hEvent = CreateEvent(NULL, FALSE, FALSE, "ExampleSlot");
    ov.Offset = 0;
    ov.OffsetHigh = 0;
    ov.hEvent = hEvent;

    // 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)  // retrieve all messages
    {
        // 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,
            &ov);

        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;
}


Mailslot Reference

The following elements can be used with mailslots.

  • Mailslot Functions


Mailslot Functions

The following functions can be used with mailslots.

Function | Description
CreateMailslot | Creates a mailslot with the specified name.
GetMailslotInfo | Retrieves information about the specified mailslot.
SetMailslotInfo | Sets the time-out value used by the specified mailslot for a read operation.


CreateMailslot

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,                            // mailslot name
  DWORD nMaxMessageSize,                     // maximum message size
  DWORD lReadTimeout,                        // read time-out interval
  LPSECURITY_ATTRIBUTES lpSecurityAttributes // inheritance option
);

Parameters

lpName
[in] Pointer 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
[in] 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
[in] 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
[in] Pointer to a SECURITY_ATTRIBUTES structure. The bInheritHandle member of the structure determines whether the returned handle can be inherited by child processes. If lpSecurityAttributes is NULL, the handle cannot be inherited. The lpSecurityDescriptor member of the structure is ignored.

Return Values

If the function succeeds, the return value is a handle to the mailslot, for use in server mailslot operations. The server side of the handle is overlapped.

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.

The system uses 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 specified name in the specified domain.
\\*\mailslot\name | Retrieves a client handle to all mailslots with the specified 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 424 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.

For an example, see Creating a Mailslot.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Mailslots Overview, Mailslot Functions, CloseHandle, CreateFile, GetMailslotInfo, SECURITY_ATTRIBUTES, SetMailslotInfo, WriteFile


GetMailslotInfo

The GetMailslotInfo function retrieves information about the specified mailslot.

BOOL GetMailslotInfo(
  HANDLE hMailslot,          // mailslot handle
  LPDWORD lpMaxMessageSize,  // maximum message size
  LPDWORD lpNextSize,        // size of next message
  LPDWORD lpMessageCount,    // number of messages
  LPDWORD lpReadTimeout      // read time-out interval
);

Parameters

hMailslot
[in] Handle to a mailslot. The CreateMailslot function must create this handle.
lpMaxMessageSize
[in] Pointer 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
[in] Pointer 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
[in] Pointer to a buffer specifying the total number of messages waiting to be read, when the function returns. This parameter can be NULL.
lpReadTimeout
[in] Pointer 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

For an example, see Reading from a Mailslot.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Mailslots Overview, Mailslot Functions, CreateMailslot, SetMailslotInfo


SetMailslotInfo

The SetMailslotInfo function sets the time-out value used by the specified mailslot for a read operation.

BOOL SetMailslotInfo(
  HANDLE hMailslot,    // mailslot handle
  DWORD lReadTimeout   // read time-out interval
);

Parameters

hMailslot
[in] Handle to a mailslot. The CreateMailslot function must create this handle.
lReadTimeout
[in] 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Mailslots Overview, Mailslot Functions, CreateMailslot, GetMailslotInfo


Network Dynamic Data Exchange

The Microsoft® Win32® API provides network dynamic data exchange (network DDE) functions to enable a process to establish conversations with processes running on different computers in a network.

  • About Network DDE
  • Using Network DDE
  • Network DDE Reference


About Network DDE

Network DDE is used to initiate and maintain the network connections needed for DDE conversations between applications running on different computers in a network. A DDE conversation is the interaction between client and server applications. You use network DDE along with DDE and the DDE management library (DDEML) in your application.

DDE is a form of interprocess communication that uses shared memory to exchange data between applications. Applications can use DDE for one time data transfers or for ongoing exchanges and updating data. For more information on DDE, see Dynamic Data Exchange.

DDEML 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 functions provided by the DDEML to manage DDE conversations. For more information on DDEML, see Dynamic Data Exchange Management Library.

Network DDE Files

To use the API elements of network DDE, you must include the NDDEAPI.H header file in your source files and include NDDEAPI.LIB file on your link line. You must also make sure that the NDDEAPI.DLL file is loaded.

  • Windows 95/98: The system includes a 16-bit NDDEAPI.DLL. However, there is no 32-bit NDDEAPI.DLL. Therefore, on Windows® 95/98, Win32-based applications that use network DDE functions need to thunk to the functions in the 16-bit NDDEAPI.DLL.
  • Win32s: The network DDE functions are not supported. Therefore, you will need to either use the DDESHARE utility or thunk to the functions in the NDDEAPI.DLL provided with Windows for Workgroups.

For more information, see the following topics:

  • Network DDE Agent
  • DDE Shares
  • Trusted Shares and Security
  • Managing DDE Shares


Network DDE Agent

The network DDE agent starts network DDE if it detects local network DDE activity. It does not detect a remote client trying to connect. Therefore, before any client can successfully connect, network DDE must be started on the server computer. Note that network DDE is not started by default. To start network DDE, run NETDDE.EXE. This file is located in your Windows directory.

The network DDE agent also starts the applications necessary for network DDE. After network DDE is started, DDE conversations are controlled through a network DDE window associated with one of the network DDE applications. This application acts as a proxy. It communicates with all local and remote DDE applications.


DDE Shares

DDE shares are a machine resource. They are similar to file shares because they are used to control access to a resource. With file shares, the resource is a file. With DDE shares, the resource is dynamically exchanged data. The type of data exchanged is determined by the server application that supplies the data and the client application that requests the data.

The server calls the NDdeShareAdd function to create the DDE share, which is stored in the DDE share database manager (DSDM).

The client starts the DDE conversation by connecting to the DDE share. The client must call the DdeInitialize function to initialize DDEML and call the DdeConnect function to connect to the DDE share. In the DdeConnect call, the client specifies the service name

\\<ComputerName>\NDDE$

where <ComputerName> is the name of the computer running the server application. The NDDE$ indicates that the topic provided to DdeConnect is the DDE share name on the remote computer named <ComputerName>.

There are three types of DDE shares: old style, new style, and static. It is typical to support only the static type. The names of static shares follow the convention <ShareName>$.


Trusted Shares and Security

Trusted Shares

When a client user connects to a DDE share from a remote computer, network DDE accepts the request only if the following statements are true:

  • The user who created the share has granted trusted status to the share by calling NDdeSetTrustedShare. Only the creator of the share can grant trusted status to the share. Not even an administrator can grant trusted status to a DDE share that was created by a different user.
  • The user who created the share is currently logged on to the server computer.

The process of granting trusted status to a share adds the share to the logged-on user's trusted shares list in the DSDM. This creates a trust relationship between the server and its clients. Once a DDE share has trusted status, clients can connect to it as long as the user that created the share is logged on. When the client connects to the share from a remote computer, network DDE accepts the request only if the share is listed in the logged-on user's trusted shares list in the DSDM.

Security

Network DDE performs an additional security check when the client requests data or a link. It checks that the server has granted the remote user the necessary permission for the operation. The server controls access to the share through the pSD parameter of the NDdeShareAdd function. This parameter specifies the security descriptor. If this parameter is NULL, the function creates a default security descriptor that grants full access to the creator of the share and grants read and link permission to all other users. To grant or deny additional permissions to individual users or groups of users, create and use a security descriptor. For more information on security descriptors, see Access Control.

To obtain the security descriptor for an existing DDE share, call the NDdeGetShareSecurity function. You can edit the information and then update the security descriptor for the share by using the NDdeSetShareSecurity function.


Managing DDE Shares

Network DDE provides functions that allow you to delete a share, get or set share information, or enumerate shares.

  • Deleting a DDE Share A server can remove a DDE share by using the NDdeShareDel function.
  • Getting and Setting DDE Share Information You can retrieve information about a DDE share by using the NDdeShareGetInfo function. You can also change information about the share by using the NDdeShareSetInfo function.
  • Enumerating DDE Shares You can enumerate the existing DDE shares for a computer by using the NDdeShareEnum function. You can enumerate the trusted DDE shares by using the NDdeTrustedShareEnum function.

    You can enumerate the users connected to your DDE shares by using the NetSessionEnum function.

  • Changing the DDE Share Name To change the name of a DDE share, an application must delete the old share and create a new share.

To change the share name

  1. Retrieve the share information using NDdeShareGetInfo.
  2. Remove the share using NDdeShareDel.
  3. Change the lpszShareName member of the NDDESHAREINFO structure returned by NDdeShareGetInfo.
  4. Pass the modified NDDESHAREINFO structure to NDdeShareAdd.


Using Network DDE

The examples in this section demonstrate the following tasks:

  • Creating a DDE share
  • Granting trusted status to a DDE share
  • Establishing a network DDE conversation
  • Displaying errors to the user


Creating a DDE Share

The following topics describe two methods for creating DDE shares:

  • Using NDdeShareAdd to Create a DDE Share
  • Using DDESHARE to Create a DDE Share

Your server application should use NDdeShareAdd to create a DDE share. However, you may wish to use DDESHARE on Win32s instead of thunking to the 16-bit NDdeShareAdd.


Using NDdeShareAdd to Create a DDE Share

The NDdeShareAdd function is used by a DDE server application to create a DDE share.

Before creating a DDE share, it is a good idea to verify that the proposed share name and topic name are valid by using the NDdeIsValidShareName and NDdeIsValidAppTopicList functions. These functions are also called by NDdeShareAdd.

The following example demonstrates how to create a DDE share. It uses a NULL discretionary access control list (DACL) to grant write access to all users. Note that this is not the same as specifying NULL in the pSD parameter of NDdeShareAdd.

BOOL MyCreateDdeShare( LPTSTR lpszShareName, LPTSTR lpszTopicList )
{
   NDDESHAREINFO ndsi;
   PSECURITY_DESCRIPTOR pSD = NULL;

// Where lpszShareName is the share name.
   if( NDdeIsValidShareName( lpszShareName ) == FALSE )
      return FALSE;

// Where lpszTopicList is a list of null-terminated strings terminated
// by another null character.
   if( NDdeIsValidAppTopicList( lpszTopicList ) == FALSE )
      return FALSE;

// Fill in the NDDESHAREINFO structure.
   ndsi.lRevision = 1;
   ndsi.lpszShareName = lpszShareName;
   ndsi.lShareType = SHARE_TYPE_STATIC;
   ndsi.lpszAppTopicList = lpszTopicList;
   ndsi.fSharedFlag = TRUE;
   ndsi.fService = FALSE;
   ndsi.fStartAppFlag = TRUE;
   ndsi.nCmdShow = SW_SHOWNORMAL;
   ndsi.cNumItems = 0;
   ndsi.lpszItemList = "";

// Create a security descriptor to allow write access.
   pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(
                                   LPTR,
                                   SECURITY_DESCRIPTOR_MIN_LENGTH );
   InitializeSecurityDescriptor( pSD, SECURITY_DESCRIPTOR_REVISION );
   SetSecurityDescriptorDacl( pSD, TRUE, (PACL)NULL, FALSE );

// Delete possible old DDE share.
   NDdeShareDel(
      NULL,
      lpszShareName,
      0
     );

// Create the DDE share.
   NDdeShareAdd(
      NULL,
      2,
      pSD,
      (LPBYTE)&ndsi,
      sizeof(NDDESHAREINFO)
     );

   LocalFree( pSD );
   return TRUE;
}

The following example shows how you could call the MyCreateDdeShare function to create the share MyDdeShare$:

char *TopicList = "\0\0MyApp|MyTopic\0\0";

MyCreateDdeShare( "MyDdeShare$", TopicList );

This share name ends with a dollar sign ($), indicating that it is a static DDE share. Topic strings are provided only for the static-type DDE share.


Using DDESHARE to Create a DDE Share

Windows for Workgroups and Windows NT/Windows 2000 provide the DDESHARE utility so that users can manage DDE shares.

To create a DDE share

  1. On the Shares menu, click DDE Shares. DDESHARE displays the following dialog box:

  2. Click the Add a Share button. DDESHARE displays the following dialog box:

  3. Fill in the Share Name, Application Name, and Topic Name text boxes, then click OK.


Granting Trusted Status To a DDE Share

The following topics describe two methods for granting trusted status to DDE shares:

  • Using NDdeSetTrustedShare to Grant Trusted Status
  • Using DDESHARE to Grant Trusted Status

Your server application should use NDdeSetTrustedShare to grant trusted status to a DDE share. However, you may wish to use DDESHARE on Win32s instead of thunking to the 16-bit NDdeSetTrustedShare.


Using NDdeSetTrustedShare to Grant Trusted Status

The NDdeSetTrustedShare function is used by a DDE server to grant trusted status to a DDE share.

The following example demonstrates how to grant trusted status to a DDE share:

BOOL MyTrustShare( LPSTR lpszShareName )
{
// Grant trusted status.
   if( NDdeSetTrustedShare( NULL, lpszShareName,
         NDDE_TRUST_SHARE_INIT | NDDE_TRUST_SHARE_START
   ) == NDDE_NO_ERROR )
      return TRUE;
   else return FALSE;
}

The following example shows how you could call the MyTrustShare function to grant trusted status to the existing share MyDdeShare$:

MyTrustShare( "MyDdeShare$" );


Using DDESHARE to Grant Trusted Status

Windows for Workgroups and Windows NT/Windows 2000 provide the DDESHARE utility so that users can manage DDE shares.

To grant trusted status

  1. On the Shares menu, click DDE Shares. DDESHARE displays the following dialog box:

  2. Click the Trust Share button. DDESHARE displays the following dialog box:

  3. Choose the options you want, click the Set button, and then click OK.


Establishing a Network DDE Conversation

Establishing a conversation between a client application and a server application on different computers is similar to establishing a conversation between a client and server on the same computer. The difference is that the client specifies a computer and a DDE share, rather than an application and a topic.

The first step is for the server to register with the DDEML by calling the DdeInitialize function. This call requires a pointer to the application-defined DDE callback function DdeCallback. The server also registers the service name that the DDE server supports by calling the DdeNameService function.

DWORD g_idInst;

BOOL MyDdeShareInit( LPTSTR lpszServer, PFNCALLBACK DdeCallback )
{
   HSZ hszService;
   char ServerBuf[MAX_COMPUTERNAME_LENGTH+8];

// Register the server application.
   if( DdeInitialize(
      &g_idInst,
      (PFNCALLBACK) DdeCallback,
      APPCLASS_STANDARD | CBF_FAIL_SELFCONNECTIONS |
      CBF_FAIL_REQUESTS | CBF_FAIL_EXECUTES,
      0L
   ) != DMLERR_NO_ERROR )
      return FALSE;

// Check if "\\server" or just "server" is specified.
   if( lpszServer[0] == '\\' )
      wsprintf( ServerBuf, "%s\\NDDE$", lpszServer );
   else wsprintf( ServerBuf, "\\\\%s\\NDDE$", lpszServer );

// Register the service names.
   hszService = DdeCreateStringHandle( g_idInst, ServerBuf, 0 );
   DdeNameService(
      g_idInst,
      hszService,
      0,
      DNS_REGISTER
     );

   DdeFreeStringHandle( g_idInst, hszService );
   return TRUE;
}

The following example shows how you could call the MyConnect function to initialize DDEML for the server application on computer ServerA:

// Application-supplied callback function.
HDDEDATA CALLBACK DdeCallback( UINT iType, UINT iFmt, HCONV hConv,
   HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2 )
{
   switch( iType )
   {
      case XTYP_CONNECT:
      // Validate topic for connection.
         ...
         return (HDDEDATA) TRUE;
      ...
      default:
         return (HDDEDATA) 0;
   }
}

MyDdeShareInit( "ServerA", DdeCallback );

As with any DDE conversation, the client and server applications must cooperate to establish a conversation. For network DDE, the client must have the computer name and the share name. The client then uses the DdeConnect function to establish a network DDE conversation.

HCONV g_hConv;

BOOL MyConnect( LPSTR lpszServer, LPTSTR lpszTopic )
{
   HSZ hszServer, hszTopic;
   char ServerBuf[MAX_COMPUTERNAME_LENGTH+8];

// Register the client application.
   if( DdeInitialize(
      &g_idInst,
      (PFNCALLBACK) DdeCallback,
      APPCLASS_STANDARD | CBF_FAIL_SELFCONNECTIONS |
      CBF_FAIL_REQUESTS | CBF_FAIL_EXECUTES,
      0L
   ) != DMLERR_NO_ERROR )
      return FALSE;

// Check if "\\server" or just "server" is specified.
   if( lpszServer[0] == '\\' )
      wsprintf( ServerBuf, "%s\\NDDE$", lpszServer );
   else wsprintf( ServerBuf, "\\\\%s\\NDDE$", lpszServer );

   hszServer = DdeCreateStringHandle(g_idInst, ServerBuf, 0);
   hszTopic = DdeCreateStringHandle(g_idInst, lpszTopic, 0);

   if( (g_hConv = DdeConnect(g_idInst,
      hszServer,
      hszTopic,
      NULL )
   ) == 0 )
      return FALSE;

   DdeFreeStringHandle( g_idInst, hszServer );
   DdeFreeStringHandle( g_idInst, hszTopic );
   return TRUE;
}

The following example shows how you could call this function to connect to the DDE share MyDdeShare$ on computer ServerA:

// Application-supplied callback function.
HDDEDATA CALLBACK DdeCallback( UINT iType, UINT iFmt, HCONV hConv,
   HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2 )
{
   switch( iType )
   {
      ...
      default:
         return (HDDEDATA) 0;
   }
}

MyConnect( "ServerA", "MyDdeShare$" );


Displaying Errors to the User

Whenever a network DDE function returns an error value, you can retrieve an error message suitable for displaying to a user by using the NDdeGetErrorString function.

DisplayNDdeErrorString( UINT uCode, LPTSTR lpszTitle )
{
   char buf[256];

   NDdeGetErrorString(
      uCode,
      buf,
      sizeof(buf)
     );
   MessageBox( NULL, buf, lpszTitle, MB_ICONEXCLAMATION | MB_OK );
}


Network DDE Reference

This following elements are used with network DDE.

  • Network DDE Functions
  • Network DDE Structures


Network DDE Functions

The following functions are used with network DDE.

Function | Description
NDdeGetErrorString | Converts an error code returned by a network DDE function into an error string that explains the returned error code.
NDdeGetShareSecurity | Retrieves the security descriptor associated with the DDE share.
NDdeGetTrustedShare | Retrieves the options associated with a DDE share that is in the server user's list of trusted shares.
NDdeIsValidAppTopicList | Determines whether an application and topic string ("AppName|TopicName") uses the proper syntax.
NDdeIsValidShareName | Determines whether a share name uses the proper syntax.
NDdeSetShareSecurity | Sets the security descriptor associated with the DDE share.
NDdeSetTrustedShare | Grants the specified DDE share trusted status within the current user's context.
NDdeShareAdd | Creates and adds a new DDE share to the DDE share database manager (DSDM).
NDdeShareDel | Deletes a DDE share from the DSDM.
NDdeShareEnum | Retrieves the list of available DDE shares.
NDdeShareGetInfo | Retrieves DDE share information.
NDdeShareSetInfo | Sets DDE share information.
NDdeTrustedShareEnum | Retrieves the names of all network DDE shares that are trusted in the context of the calling process.


NDdeGetErrorString

The NDdeGetErrorString function converts an error code returned by a network DDE function into an error string that explains the returned error code.

UINT NDdeGetErrorString(
  UINT uErrorCode,         // error code
  LPTSTR lpszErrorString,  // error string buffer
  DWORD cBufSize           // size of buffer
);

Parameters

uErrorCode
[in] Error code to be converted into an error string.
lpszErrorString
[out] Pointer to a buffer that receives the translated error string. This parameter cannot be NULL. If the buffer is not large enough to store the complete error string, the string is truncated.
cBufSize
[in] Specifies the size of the buffer, in TCHARs, to receive the error string.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions


NDdeGetShareSecurity

The NDdeGetShareSecurity function retrieves the security descriptor associated with the DDE share. This is done usually for editing.

UINT NDdeGetShareSecurity(
  LPTSTR lpszServer,        // server name
  LPTSTR lpszShareName,     // share name
  SECURITY_INFORMATION si,  // requested information
  PSECURITY_DESCRIPTOR pSD, // SD buffer
  DWORD cbSD,               // size of SD buffer
  LPDWORD lpcbsdRequired    // required size of SD buffer
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server on which the DSDM resides.
lpszShareName
[in] Pointer to a string that specifies the name of the share whose security descriptor is to be retrieved from the DSDM. This parameter cannot be NULL.
si
[in] A SECURITY_INFORMATION value that specifies the security information to be retrieved from the security descriptor associated with the share.
pSD
[out] Pointer to a SECURITY_DESCRIPTOR structure that receives the 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
[in] Specifies the size of the pSD buffer. This parameter must be zero if pSD is NULL.
lpcbsdRequired
[out] Pointer to the variable that receives the actual size of the retrieved security descriptor. This parameter cannot be NULL.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions, SECURITY_INFORMATION, NDdeSetShareSecurity


NDdeGetTrustedShare

The NDdeGetTrustedShare function retrieves the options associated with a DDE share that is in the server user's list of trusted shares.

UINT NDdeGetTrustedShare(
  LPTSTR lpszServer,        // server name
  LPTSTR lpszShareName,     // share name
  LPDWORD lpdwTrustOptions, // trust options in effect
  LPDWORD lpdwShareModId0,  // first part of identifier
  LPDWORD lpdwShareModId1   // second part of identifier
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server on which the DSDM resides.
lpszShareName
[in] Pointer to a string that specifies the share name whose trusted status is being queried. This parameter cannot be NULL.
lpdwTrustOptions
[out] Pointer to a variable that receives the trust options. This parameter cannot be NULL. The following trust 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 | Override the show state specified in the DDE share DSDM.
NDDE_CMD_SHOW_MASK | Mask used to obtain the value used to override the DDE share show state, if NDDE_TRUST_CMD_SHOW is set.

lpdwShareModId0
[out] Pointer to a variable that receives the first part of the trusted share modify identifier. This parameter cannot be NULL.
lpdwShareModId1
[out] Pointer to a variable that receives the second part of the trusted share modify identifier. This parameter cannot be NULL.

Return Values

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 DSDM at the time the DDE share was initially granted trusted 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 network DDE agent purges obsolete shares on the user's behalf.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions, NDdeSetTrustedShare


NDdeIsValidAppTopicList

The NDdeIsValidAppTopicList function determines whether an application and topic string ("AppName|TopicName") uses the proper syntax.

BOOL NDdeIsValidAppTopicList(
  LPTSTR targetTopic     // application and topic string
);

Parameters

targetTopic
[in] Pointer to the application and topic string to validate. This parameter cannot be NULL.

Return Values

If the targetTopic parameter has valid syntax, the return value is nonzero.

If the function fails, the return value is zero.

Remarks

This function is also called by NDdeShareAdd when it creates the DDE share.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions, NDdeShareAdd


NDdeIsValidShareName

The NDdeIsValidShareName function determines whether a share name uses the proper syntax.

BOOL NDdeIsValidShareName(
  LPTSTR shareName   // share name
);

Parameters

shareName
[in] Pointer to a share name to validate. This parameter cannot be NULL.

Return Values

If the share name has valid syntax, the return value is nonzero.

If the share name does not have valid syntax, the return value is zero.

Remarks

This function is also called by NDdeShareAdd when it creates the DDE share.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions, NDdeShareAdd


NDdeSetShareSecurity

The NDdeSetShareSecurity function sets 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 name
  LPTSTR lpszShareName,      // share name
  SECURITY_INFORMATION si,   // information type
  PSECURITY_DESCRIPTOR pSD   // security descriptor
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server whose DSDM is to be modified.
lpszShareName
[in] Pointer to a string that specifies the name of the share whose security descriptor is to be modified. This parameter cannot be NULL.
si
[in] A SECURITY_INFORMATION value that identifies the security information to retrieve.
pSD
[in] Pointer to a SECURITY_DESCRIPTOR structure that contains security information. This parameter cannot be NULL and should point to a valid security descriptor.

Return Values

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 privilege; the share creator has this privilege.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions, SECURITY_INFORMATION, NDdeGetShareSecurity


NDdeSetTrustedShare

The NDdeSetTrustedShare function grants the specified DDE share trusted status within the current user's context.

UINT NDdeSetTrustedShare(
  LPTSTR lpszServer,     // server name
  LPTSTR lpszShareName,  // share name
  DWORD dwTrustOptions   // trust options
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server whose DSDM is to be modified.
lpszShareName
[in] Pointer to a string that specifies the name of the share to be granted trusted status. This parameter cannot be NULL.
dwTrustOptions
[in] Specifies the options affecting the trusted status of the DDE share. The following trust 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 | Override the show state specified in the DDE share DSDM.
NDDE_CMD_SHOW_MASK | Mask used to obtain the value used to override the DDE share show state, if NDDE_TRUST_CMD_SHOW is set.

Return Values

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 DDE share must first be created with NDdeShareAdd.

If NDdeSetTrustedShare is called with dwTrustOptions set to zero, the trusted share loses its trusted status.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions, NDdeShareAdd


NDdeShareAdd

The NDdeShareAdd function creates and adds a new DDE share to the DDE share database manager (DSDM).

UINT NDdeShareAdd(
  LPTSTR lpszServer,         // server name
  UINT nLevel,               // information level
  PSECURITY_DESCRIPTOR pSD,  // initial security descriptor
  LPBYTE lpBuffer,           // address of NDDESHAREINFO
  DWORD cBufSize             // size of supplied buffer
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server whose DSDM is to be modified.
nLevel
[in] Specifies the information level. This parameter must be 2.
pSD
[in] Pointer to a SECURITY_DESCRIPTOR structure to be associated with this share and against which access checks will be performed on subsequent initiates to this share. This parameter can be NULL, in which case the DSDM creates a default security descriptor that grants "Full Control" to the owner and "Read and Link" to everyone.
lpBuffer
[in] Pointer to the NDDESHAREINFO structure that defines the ApplicationTopic list associated with the DDE share being created as well as other parameters. This parameter cannot be NULL.
cBufSize
[in] Specifies the size of the lpBuffer structure, in bytes. This parameter cannot be zero.

Return Values

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

Before a client can connect to the DDE share, it must be trusted with NDdeSetTrustedShare.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions, NDDESHAREINFO, NDdeSetTrustedShare


NDdeShareDel

The NDdeShareDel function deletes a DDE share from the DDE share database manager (DSDM).

UINT NDdeShareDel(
  LPTSTR lpszServer,     // server name
  LPTSTR lpszShareName,  // share name
  UINT wReserved         // reserved; must be zero
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server whose DSDM is to be modified.
lpszShareName
[in] Pointer to a string that specifies the name of the share to be deleted from the DSDM. This parameter cannot be NULL.
wReserved
[in] This parameter must be zero.

Return Values

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, you must have the appropriate privilege. The share creator has delete privilege.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions


NDdeShareEnum

The NDdeShareEnum function retrieves the list of available DDE shares.

UINT NDdeShareEnum(
  LPTSTR lpszServer,           // server name
  UINT nLevel,                 // must be zero
  LPBYTE lpBuffer,             // buffer
  DWORD cBufSize,              // size of buffer
  LPDWORD lpnEntriesRead,      // number of names returned
  LPDWORD lpcbTotalAvailable   // number of bytes available
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server on which the DSDM resides.
nLevel
[in] This parameter must be zero.
lpBuffer
[out] Pointer to a buffer that receives 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 parameter.
cBufSize
[in] Specifies the size of the lpBuffer buffer, in bytes. This parameter must be zero if lpBuffer is NULL.
lpnEntriesRead
[out] Pointer to a variable that receives the total number of shares being enumerated. This parameter cannot be NULL.
lpcbTotalAvailable
[out] Pointer to a variable that receives the total number of bytes needed in the buffer to store the list of DDE shares. This parameter cannot be NULL.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions


NDdeShareGetInfo

The NDdeShareGetInfo function retrieves DDE share information. This is usually done for editing.

UINT NDdeShareGetInfo(
  LPTSTR lpszServer,          // server name
  LPTSTR lpszShareName,       // share name
  UINT nLevel,                // information level
  LPBYTE lpBuffer,            // share information buffer
  DWORD cBufSize,             // size of buffer
  LPDWORD lpnTotalAvailable,  // number of bytes available
  LPWORD lpnItems             // selection mask
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server on which the DSDM resides.
lpszShareName
[in] Pointer to the share name whose information is to be retrieved from the DSDM. This parameter must not be NULL.
nLevel
[in] This parameter must be 2.
lpBuffer
[out] Pointer to a buffer that receives the NDDESHAREINFO structure and associated data pointed to by its members. This parameter 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
[in] Specifies the size of the lpBuffer buffer, in bytes. If lpBuffer is NULL, then cBufSize should be zero.
lpnTotalAvailable
[out] Pointer to a variable that receives the total number of bytes needed to store the requested share information. This parameter cannot be NULL.
lpnItems
[in] Pointer to an item selection mask for partial share information retrieval. For Windows NT version 3.1, the item selection mask must be zero.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions, NDDESHAREINFO, NDdeShareSetInfo


NDdeShareSetInfo

The NDdeShareSetInfo function sets DDE share information. This is usually done after editing.

UINT NDdeShareSetInfo(
  LPTSTR lpszServer,     // server name
  LPTSTR lpszShareName,  // share name
  UINT nLevel,           // information level
  LPBYTE lpBuffer,       // share information buffer
  DWORD cBufSize,        // size of buffer
  WORD sParmNum          // parameter index
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server whose DSDM is to be modified.
lpszShareName
[in] Pointer to a string that specifies the name of the share name whose information is to be modified. This parameter cannot be NULL.
nLevel
[in] This parameter must be 2.
lpBuffer
[in] Pointer to the NDDESHAREINFO structure that specifies the 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. This parameter cannot be NULL.
cBufSize
[in] Specifies the size of the lpBuffer buffer, in bytes.
sParmNum
[in] Specifies the parameter index to be modified. The current implementation does not support partial modification; therefore, this parameter must be zero.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions, NDDESHAREINFO, NDdeShareGetInfo


NDdeTrustedShareEnum

The NDdeTrustedShareEnum function retrieves the names of all network DDE shares that are trusted in the context of the calling process.

UINT NDdeTrustedShareEnum(
  LPTSTR lpszServer,           // server name
  UINT nLevel,                 // information level
  LPBYTE lpBuffer,             // buffer
  DWORD cBufSize,              // size of buffer
  LPDWORD lpnEntriesRead,      // number of names returned
  LPDWORD lpcbTotalAvailable   // number of bytes available
);

Parameters

lpszServer
[in] Pointer to a string that specifies the name of the server on which the DSDM resides.
nLevel
[in] This parameter must be zero.
lpBuffer
[out] Pointer to a buffer that receives the list of trusted DDE shares. The list of trusted DDE shares is returned 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
[in] Specifies the size of the lpBuffer buffer, in bytes. This parameter must be zero if lpBuffer is NULL.
lpnEntriesRead
[out] Pointer to a variable that receives the total number of trusted shares being enumerated. This parameter cannot be NULL.
lpcbTotalAvailable
[out] Pointer to a variable that receives the total number of bytes needed to store the list of trusted DDE shares. This parameter cannot be NULL.

Return Values

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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Nddeapi.h.
Library: Use Nddeapi.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Network Dynamic Data Exchange Overview, Network DDE Functions


Network DDE Structures

The following structure is used with network DDE.

NDDESHAREINFO


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.

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, *PNDDESHAREINFO;

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 allowing DDE communication.
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, this value is sent to the application through 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 member 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Header: Declared in Nddeapi.h.

See Also

Network Dynamic Data Exchange Overview, Network DDE Structures, NDdeSetShareSecurity, NDdeShareSetInfo, WinMain


Pipes

A pipe is a section of shared memory that processes use for communication. The process that creates a pipe is the pipe server. A process that connects to a pipe is a pipe client. One process writes information to the pipe, then the other process reads the information from the pipe. This overview describes how to create, manage, and use pipes.

  • About Pipes
  • Using Pipes
  • Pipe Reference


About Pipes

The Microsoft® Win32® API supports both anonymous pipes and named pipes. Anonymous pipes require less overhead than named pipes, but offer limited services.

The term pipe, as used here, implies that a pipe is used as an information conduit. Conceptually, a pipe has two ends. A one-way pipe allows the process at one end to write to the pipe, and allows the process at the other end to read from the pipe. A two-way (or duplex) pipe allows a process to read and write from its end of the pipe.

  • Anonymous Pipes
  • Named Pipes


Anonymous Pipes

An anonymous pipe is an unnamed, one-way pipe that typically transfers data between a parent process and a child process. Anonymous pipes are always local; they cannot be used for communication over a network.

Windows NT/2000: Anonymous pipes are implemented using a named pipe with a unique name. Therefore, you can often pass a handle to an anonymous pipe to a function that requires a handle to a named pipe.


Anonymous Pipe Operations

The CreatePipe function creates an anonymous pipe and returns two handles: a read handle to the pipe and a write handle to the pipe. The read handle has read-only access to the pipe, and the write handle has write-only access to the pipe. To communicate using the pipe, the pipe server must pass one of the handles to another process. Usually, this is done through inheritance; that is, the process allows the handle to be inherited by a child process. The process can also send the handle to an unrelated process using some form of interprocess communication, such as DDE or shared memory.

A pipe server can send either the read handle or the write handle to the pipe client, depending on whether the client should use the anonymous pipe to send information or receive information. To read from the pipe, use the pipe's read handle in a call to the ReadFile function. The ReadFile call returns when another process has written to the pipe. The ReadFile call can also return if all write handles to the pipe have been closed or if an error occurs before the read operation has been completed.

To write to the pipe, use the pipe's write handle in a call to the WriteFile function. The WriteFile call does not return until it has written the specified number of bytes to the pipe or an error occurs. If the pipe buffer is full and there are more bytes to be written, WriteFile does not return until another process reads from the pipe, making more buffer space available. The pipe server specifies the buffer size for the pipe when it calls CreatePipe.

Asynchronous (overlapped) read and write operations are not supported by anonymous pipes. This means that you cannot use the ReadFileEx and WriteFileEx functions with anonymous pipes. In addition, the lpOverLapped parameter of ReadFile and WriteFile is ignored when these functions are used with anonymous pipes.

An anonymous pipe exists until all pipe handles, both read and write, have been closed. A process can close its pipe handles by using the CloseHandle function. All pipe handles are also closed when the process terminates.


Pipe Handle Inheritance

The pipe server controls whether its handles can be inherited in the following ways:

  • The CreatePipe function receives a SECURITY_ATTRIBUTES structure. If the pipe server sets the bInheritHandle member of this structure to TRUE, the handles created by CreatePipe can be inherited.
  • The pipe server can use the DuplicateHandle function to change the inheritance of a pipe handle. The pipe server can create a noninheritable duplicate of an inheritable pipe handle or an inheritable duplicate of a noninheritable pipe handle.
  • The CreateProcess function enables the pipe server to specify whether a child process inherits all or none of its inheritable handles.

When a child process inherits a pipe handle, the system enables the process to access the pipe. However, the parent process must communicate the handle value to the child process. The parent process typically does this by redirecting the standard output handle to the child process, as shown in the following steps:

  1. Call the GetStdHandle function to get the current standard output handle; save this handle so you can restore the original standard output handle after the child process has been created.
  2. Call the SetStdHandle function to set the standard output handle to the write handle to the pipe. Now the parent process can create the child process.
  3. Call the CloseHandle function to close the write handle to the pipe. After the child process inherits the write handle, the parent process no longer needs its copy.
  4. Call SetStdHandle to restore the original standard output handle.

The child process uses the GetStdHandle function to get its standard output handle, which is now a handle to the write end of a pipe. The child process then uses the WriteFile function to send its output to the pipe. When the child has finished with the pipe, it should close the pipe handle by calling CloseHandle or by terminating, which automatically closes the handle.

The parent process uses the ReadFile function to receive input from the pipe. Data is written to an anonymous pipe as a stream of bytes. This means that the parent process reading from a pipe cannot distinguish between the bytes written in separate write operations, unless both the parent and child processes use a protocol to indicate where the write operation ends. When all write handles to the pipe are closed, the ReadFile function returns zero. It is important for the parent process to close its handle to the write end of the pipe before calling ReadFile. If this is not done, the ReadFile operation cannot return zero because the parent process has an open handle to the write end of the pipe.

The procedure for redirecting the standard input handle is similar to that for redirecting the standard output handle, except that the pipe's read handle is used as the child's standard input handle. In this case, the parent process must ensure that the child process does not inherit the pipe's write handle. If this is not done, the ReadFile operation performed by the child process cannot return zero because the child process has an open handle to the write end of the pipe.

For an example program that uses anonymous pipes to redirect the standard handles of a child process, see Creating a Child Process with Redirected Input and Output.


Anonymous Pipe Security

Windows NT/Windows 2000 security enables you to control access to anonymous pipes. For more information about security, see Access-Control Model.

You can specify a security descriptor for a pipe when you call the CreatePipe function. The security descriptor controls access to both the read and write ends of the pipe. To retrieve a pipe's security descriptor, call the GetSecurityInfo function. To change a pipe's security descriptor, call the SetSecurityInfo function.

The CreatePipe function returns two handles to the anonymous pipe: a read handle with GENERIC_READ and SYNCHRONIZE access; and a write handle with GENERIC_WRITE and SYNCHRONIZE access. GENERIC_READ and GENERIC_WRITE access use the same access rights mapping as for named pipes.

GENERIC_READ access for an anonymous pipe combines the rights to read data from the pipe, read pipe attributes, read extended attributes, and read the pipe's DACL.

GENERIC_WRITE access for an anonymous pipe combines the rights to write data to the pipe, append data to it, write pipe attributes, write extended attributes, and read the pipe's DACL.


Named Pipes

A named pipe is a named, one-way or duplex pipe for communication between the pipe server and one or more pipe clients. 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. The use of instances enables multiple pipe clients to use the same named pipe simultaneously.

Any process can access named pipes, subject to security checks, making named pipes an easy form of communication between related or unrelated processes. Named pipes can be used to provide communication between processes on the same computer or between processes on different computers across a network.

Any process can act as both a server and a client, making peer-to-peer communication possible. As used here, the term pipe server refers to a process that creates a named pipe, and the term pipe client refers to a process that connects to an instance of a named pipe.


Pipe Names

Each named pipe has a unique name that distinguishes it from other named pipes in the system's list of named objects. A pipe server specifies a name for the pipe when it calls the CreateNamedPipe function to create one or more instances of a named pipe. Pipe clients specify the pipe name when they call the CreateFile or CallNamedPipe function to connect to an instance of the named pipe.

Use the following form when specifying the name of a pipe in the CreateFile, WaitNamedPipe, or CallNamedPipe function:

\\ServerName\pipe\PipeName

where ServerName is either the name of a remote computer or a period, to specify the local computer. The pipe name string specified by PipeName 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.

The pipe server cannot create a pipe on another computer, so CreateNamedPipe must use a period for the server name, as shown in the following example.

\\.\pipe\PipeName

A pipe server often passes the pipe name to its pipe clients so they can connect to the pipe. Otherwise, the clients must know the pipe name at compile time.


Named Pipe Open Modes

The pipe server specifies the pipe access, overlap, and write-through modes in the dwOpenMode parameter of the CreateNamedPipe function. The pipe clients can specify these open modes for their pipe handles using the CreateFile function.

Access Mode

Setting the pipe access mode is equivalent to specifying read or write access associated with the pipe server's handles. The following table shows the CreateFile equivalent for each access mode you can specify with CreateNamedPipe.

CreateNamedPipe Access Mode | CreateFile Equivalent
PIPE_ACCESS_INBOUND | GENERIC_READ (server only reads and client only writes)
PIPE_ACCESS_OUTBOUND | GENERIC_WRITE (server only writes and client only reads)
PIPE_ACCESS_DUPLEX | GENERIC_READ | GENERIC_WRITE (server and client both read and write)

Pipe clients using CreateFile to connect to a named pipe must specify an access mode in the dwDesiredAccess parameter that is compatible with the access mode specified by the pipe server. For example, a client must specify GENERIC_READ access for a pipe created with PIPE_ACCESS_OUTBOUND. The access modes must be the same for all instances of a pipe.

Overlapped Mode

In overlapped mode, functions performing lengthy read, write, and connect operations can return immediately. This enables the thread to perform other operations while a time-consuming operation is executing in the background. To specify overlapped mode, use the FILE_FLAG_OVERLAPPED flag. For more information, see Synchronous and Overlapped Input and Output.

The CreateFile function allows the pipe client to set overlapped mode (FILE_FLAG_OVERLAPPED) for its pipe handles using the dwFlagsAndAttributes parameter.

Write-Through Mode

Specify write-through mode with FILE_FLAG_WRITE_THROUGH. This mode affects only write operations to byte-type pipes between pipe clients and pipe servers on different computers. In write-through mode, the functions that write to a named pipe do not return until the data is transmitted across the network and into the pipe's buffer on the remote computer. Write-through mode is useful for applications that require synchronization for every write operation.

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 the system to combine multiple write operations into a single network transmission. This means that a write operation can be successfully completed after the system puts the data in the outbound buffer, but before the system transmits it across the network.

The CreateFile function allows the pipe client to set write-through mode (FILE_FLAG_WRITE_THROUGH) for its pipe handles using the dwFlagsAndAttributes parameter. 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.

A pipe client 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.


Named Pipe Type, Read, and Wait Modes

The pipe server specifies the pipe type, read, and wait modes in the dwPipeMode parameter of the CreateNamedPipe function. Pipe clients can specify these pipe modes for their pipe handles using the CreateFile function.

Type Mode

The type mode of a pipe determines how data is written to a named pipe. Data can be transmitted through a named pipe as either a stream of bytes or as a stream of messages. The pipe server specifies the pipe type when calling CreateNamedPipe to create an instance of a named pipe. The type modes must be the same for all instances of a pipe.

To create a byte-type pipe, specify PIPE_TYPE_BYTE or use the default value. The 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.

To create a message-type pipe, specify PIPE_TYPE_MESSAGE. The system treats the bytes written in each write operation to the pipe as a message unit. The system always performs write operations on message-type pipes as if write-through mode were enabled.

Read Mode

The read mode of a pipe determines how data is read from a named pipe. The pipe server specifies the initial read mode for a pipe handle when calling CreateNamedPipe. Data can be read in byte-read mode or message-read mode. A handle to a byte-type pipe can be in byte-read mode only. A handle to a message-type pipe can be in either byte-read or message-read mode. For a message-type pipe, the read mode can be different for server and client handles to the same pipe instance.

To create the pipe handle in byte-read mode, specify PIPE_READMODE_BYTE or use the default value. Data is read from the pipe as a stream of bytes. A read operation is completed successfully when all available bytes in the pipe are read or when the specified number of bytes is read.

To create the pipe handle in message-read mode, specify PIPE_READMODE_MESSAGE. Data is read from the pipe as a stream of messages. A read 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 zero (the GetLastError function returns ERROR_MORE_DATA). The remainder of the message can be read using another read operation.

For a pipe client, a pipe handle returned by CreateFile is always in byte-read mode initially. Both pipe clients and pipe servers can use the SetNamedPipeHandleState function to change the read mode of a pipe handle.

Wait Mode

The wait mode of a pipe handle determines how the ReadFile, WriteFile, and ConnectNamedPipe functions handle lengthy operations. In blocking-wait mode, the functions wait indefinitely for a process on the other end of the pipe to complete an operation. In nonblocking-wait mode, the functions return immediately in situations that would otherwise require an indefinite wait.

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 zero immediately, and the GetLastError function returns ERROR_NO_DATA.

A WriteFile operation is affected by the wait mode of a pipe handle when there is insufficient space in the pipe's buffer. 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 a nonzero value 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 pipe client connects to the pipe instance by calling either the CreateFile or CallNamedPipe function. With a nonblocking-wait handle, the connect operation returns zero immediately, and the GetLastError function returns ERROR_PIPE_LISTENING.

By default, all named pipe handles returned by the CreateNamedPipe or CreateFile function are created with blocking-wait mode enabled. To create the pipe in nonblocking-wait mode, the pipe server specifies PIPE_NOWAIT when calling CreateNamedPipe.

Both pipe clients and pipe servers can change a pipe handle's wait mode by specifying either PIPE_WAIT or PIPE_NOWAIT in a call to the SetNamedPipeHandleState function.

Note The nonblocking-wait mode is supported for compatibility with Microsoft® LAN Manager version 2.0. This mode 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 operations to run in the background after the function returns. For more information about overlapped I/O, see Synchronous and Overlapped Input and Output.


Named Pipe Instances

The simplest pipe server creates a single instance of a pipe, connects to a single client, communicates with the client, disconnects from the client, closes the pipe handle, and terminates. However, it is more common for a pipe server to communicate with multiple pipe clients. A pipe server could use a single pipe instance to connect with multiple pipe clients by connecting to and disconnecting from each client in sequence, but performance would be poor. The pipe server must create multiple pipe instances to efficiently handle multiple clients simultaneously.

There are three basic strategies for servicing multiple pipe instances.

  • Create a separate thread for each instance of the pipe. For an example of a multithreaded pipe server, see Multithreaded Pipe Server.
  • Use overlapped operations by specifying an OVERLAPPED structure in the ReadFile, WriteFile, and ConnectNamedPipe functions. For an example, see Named Pipe Server Using Overlapped I/O.
  • Use overlapped operations by using the ReadFileEx and WriteFileEx functions, which specify a completion routine to be executed when the operation is completed. For an example, see Named Pipe Server Using Completion Routines.

The multithreaded pipe server is easiest to write, because the thread for each instance handles communications for a single pipe client. The system allocates processor time to each thread as needed. But each thread uses system resources, which is a disadvantage for a pipe server that handles a large number of clients.

With a single-threaded server, it is easier to coordinate operations that affect multiple clients, and it is easier to protect shared resources from simultaneous access by multiple clients. The challenge of a single-threaded server is that it requires coordination of overlapped operations to allocate processor time for handling the simultaneous needs of clients.


Named Pipe Operations

The first time the pipe server calls the CreateNamedPipe function, it uses the nMaxInstances parameter to specify the maximum number of instances of the pipe that can exist simultaneously. The server can call CreateNamedPipe repeatedly to create additional instances of the pipe, as long as it doesn't exceed the maximum number of instances. If the function succeeds, each call returns a handle to the server end of a named pipe instance.

As soon as the pipe server creates a pipe instance, a pipe client 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 pipe client can use the WaitNamedPipe function to wait until a pipe becomes available.

A pipe server can determine when a pipe client is connected to a pipe instance by calling the ConnectNamedPipe function. If the pipe handle is in blocking-wait mode, ConnectNamedPipe does not return until a client is connected.

Pipe clients and servers 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 duplex pipes if the pipe handle to 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.

The pipe server should not perform a blocking read operation until the pipe client has started. Otherwise, a race condition can occur. This typically occurs when initialization code, such as that of the C run-time library, needs to lock and examine inherited handles.

When a client and server finish using a pipe instance, the server should first call the FlushFileBuffers function, to ensure that all bytes or messages written to the pipe are read by the client. FlushFileBuffers does not return until the client has read all data from the pipe. The server then calls the DisconnectNamedPipe function to close the connection to the pipe client. This function makes the client's handle invalid, if it has not already been closed. Any unread data in the pipe is discarded. 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 information for pipes that communicate over a network. The SetNamedPipeHandleState function sets the read mode and wait modes of a pipe handle. For pipe clients 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).


Synchronous and Overlapped Input and Output

The ReadFile, WriteFile, TransactNamedPipe, and ConnectNamedPipe functions can run either synchronously or asynchronously. When a function runs synchronously, it does not return until the operation it is performing is 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 be completed. When a function runs asynchronously, it returns immediately, even if the operation has not been completed. This enables a time-consuming operation to be executed in the background while the calling thread is free to perform other tasks.

Using synchronous I/O enables a pipe server to use a loop that performs the following steps:

  1. Specify multiple event objects in a call to the wait function, and wait for one of the objects to be set to the signaled state.
  2. Use the wait function's return value to determine which overlapped operation has finished.
  3. Perform the tasks necessary to clean up the completed operation and initiate the next operation for that pipe handle. This can involve starting another overlapped operation for the same pipe handle.

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 pipe server to handle communications with multiple pipe clients efficiently. For an example, see Named Pipe Server Using Overlapped I/O.

For a pipe server to use synchronous operations to communicate with more than one client, it must create a separate thread for each pipe client so that one or more threads can run while other threads are waiting. For an example of a multithreaded pipe server that uses synchronous operations, see Multithreaded Pipe Server.

Enabling Asynchronous Operation

The ReadFile, WriteFile, TransactNamedPipe, and ConnectNamedPipe functions can be performed asynchronously only if you enable overlapped mode for the specified pipe handle and specify a valid pointer to an OVERLAPPED structure. If the OVERLAPPED pointer is NULL, the function return value can incorrectly indicate that the operation has been completed. 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.

The hEvent member of the specified OVERLAPPED structure must contain a handle to a manual-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 has finished. You should not use the pipe handle for synchronization 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 reliable 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. For more information about event objects, see Synchronization.

When ReadFile, WriteFile, TransactNamedPipe, and ConnectNamedPipe operations are performed asynchronously, one of the following 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 zero 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 zero 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.

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 finished. The completion routine is not executed until the thread that called ReadFileEx and WriteFileEx starts an alertable wait operation by calling one of the alertable wait functions with the fAlertable parameter set to TRUE. In an alertable wait operation, the functions also return when a ReadFileEx or WriteFileEx completion routine is queued for execution. A pipe server 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. For an example, see Named Pipe Server Using Completion Routines.


Named Pipe Security

Windows NT/Windows 2000 security enables you to control access to named pipes. For more information about security, see Access-Control Model.

You can specify a security descriptor for a named pipe when you call the CreateNamedPipe function. The security descriptor controls access to both client and server ends of the named pipe. To retrieve a named pipe's security descriptor, call the GetSecurityInfo function. To change the security descriptor of a named pipe, call the SetSecurityInfo function.

When a thread calls CreateNamedPipe to open a handle to the server end of an existing named pipe, the system performs an access check before returning the handle. The access check compares the thread's access token and the requested access rights against the DACL in the named pipe's security descriptor. In addition to the requested access rights, the DACL must allow the calling thread FILE_CREATE_PIPE_INSTANCE access to the named pipe.

Similarly, when a client calls the CreateFile or CallNamedPipe function to connect to the client end of a named pipe, the system performs an access check before granting access to the client.

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 the rights to read data from the pipe, read pipe attributes, read extended attributes, and read the pipe's DACL.

GENERIC_WRITE access for a named pipe combines the rights to write data to the pipe, append data to it, write pipe attributes, write extended attributes, and read the pipe's DACL.

You can request the ACCESS_SYSTEM_SECURITY access right to a named pipe object if you want to read or write the object's SACL. For more information, see Access-Control Lists (ACLs) and SACL Access Right.


Impersonating a Named Pipe Client

Impersonation is the ability of a thread to execute in a security context different from that of the process that owns the thread. A named pipe server thread can call the ImpersonateNamedPipeClient function to assume the access token of the user connected to the client end of the pipe. Impersonation enables the server thread to perform actions on behalf of the client, but within the limits of the client's security context. For example, a named pipe server can provide access to a database or file system to which the pipe server has privileged access. The client typically has some lesser level of access rights. When a pipe client sends a request to the server, the server impersonates the client and attempts 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.

The impersonation level determines the operations the server can perform while impersonating the client. By default, a server impersonates at the SecurityImpersonation impersonation level. However, when the client calls the CreateFile function to open a handle to the client end of the pipe, the client can use the SECURITY_SQOS_PRESENT flag to control the server's impersonation level.


Using Pipes

Pipes are useful in applications that must pass a continuous stream of data between processes. The examples in this section illustrate the following tasks:

  • Multithreaded pipe server
  • Named pipe server using overlapped I/O
  • Named pipe server using completion routines
  • Named pipe client
  • Transactions on named pipes


Multithreaded Pipe Server

The following example is a multithreaded pipe server. It has a main thread with a loop that creates a pipe instance and waits for a pipe client to connect. When a pipe client connects, the pipe server creates a thread to service that client and then continues to execute the loop. It is possible for a pipe client to connect successfully to the pipe instance in the interval between calls to the CreateNamedPipe and ConnectNamedPipe functions. If this happens, ConnectNamedPipe returns zero, 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 pipe client 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 attribute

      if (hPipe == INVALID_HANDLE_VALUE)
          MyErrExit("CreatePipe");

      // Wait for the client to connect; if it succeeds,
      // the function returns a nonzero value. If the function returns
      // zero, 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 attribute
            0,                 // default stack size
            (LPTHREAD_START_ROUTINE) InstanceThread,
            (LPVOID) hPipe,    // thread parameter
            0,                 // not suspended
            &dwThreadId);      // returns thread ID

         if (hThread == NULL)
            MyErrExit("CreateThread");
         else
            CloseHandle(hThread);

      }
      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);
}


Named Pipe Server Using Overlapped I/O

This topic includes an example of a single-threaded pipe server that uses overlapped operations to service simultaneous connections to multiple pipe clients. The pipe server creates a fixed number of pipe instances. Each pipe instance can be connected to a separate pipe client. When a pipe client has finished using its pipe instance, the server disconnects from the client and reuses the pipe instance to connect to a new client.

The OVERLAPPED 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 by using the event object in the OVERLAPPED structure. 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 stored in an array that is passed to the WaitForMultipleObjects function. This function waits for one of the events to be signaled, and returns the array index of the event that caused the wait operation to complete. The example in this topic uses this array 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, which requires a call to the GetOverlappedResult function. The server uses the dwState member of the structure to determine the next operation that must be performed for the pipe instance.

Overlapped ReadFile, WriteFile, and ConnectNamedPipe operations can finish by the time the function returns. Otherwise, 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 finishes, 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 an event object 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 has 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 zero and the GetLastError function returns ERROR_IO_PENDING. In this case, use the GetOverlappedResult function to retrieve the results after the operation has finished. GetOverlappedResult returns only the results of pending operations. It 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 topic 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, before disconnecting, you must wait for a signal indicating the client has finished. In the following example, the signal is the error generated by trying to read from the pipe after the pipe client 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 attribute
         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 attributes

      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, 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 zero.
   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;
}


Named Pipe Server Using Completion Routines

Like the previous example, the following example is a single-threaded pipe server that creates a message-type pipe and uses overlapped operations. The pipe servers differ, in that this example uses the extended functions ReadFileEx and WriteFileEx to perform overlapped I/O. Unlike the overlapped ReadFile and WriteFile functions, which signal an event object when completed, the extended functions specify a completion routine, which is queued for execution when the operation is finished. The pipe server uses the WaitForSingleObjectEx function, which performs an alertable wait operationthat 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 pipe server 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 start 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 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 pipe server in the previous example.

#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 WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);
VOID WINAPI 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 attribute
      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 conditions are 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 a completion routine after writing to
// the pipe, or when a new client has connected to a pipe instance. It
// starts another read operation.

VOID WINAPI 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 WINAPI 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 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 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 attributes
  if (hPipe == INVALID_HANDLE_VALUE)
      MyErrExit("CreatePipe");

// Call a subroutine to connect to the new client.

   return ConnectToNewClient(hPipe, lpoOverlap);
}


Named Pipe Client

A named pipe client 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 zero and the GetLastError function returns ERROR_PIPE_BUSY. When this happens, the named pipe client uses the WaitNamedPipe function to wait for an instance of the named pipe to become available.

The CreateFile function 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, the client can specify read, write, or read/write access; for an outbound pipe (write-only server), the client must specify read-only access; and for an inbound pipe (read-only server), the client must specify write-only access.

The handle returned by CreateFile defaults to byte-read mode, blocking-wait mode, overlapped mode disabled, and write-through mode disabled. The pipe client 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 pipe client that opens a named pipe, sets the pipe handle to message-read mode, uses the WriteFile function to send a request to the server, and uses the ReadFile function to read the server's reply. This pipe client can be used with any of the message-type servers shown in the previous examples. With a byte-type server, however, this pipe client 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 zero 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 client can read the remainder of the message using 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 and write access
         GENERIC_WRITE,
         0,              // no sharing
         NULL,           // no security attributes
         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 maximum bytes
      NULL);    // don't set maximum 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.

The TransactNamedPipe function is most commonly used by a pipe client to write a request message to the named pipe server and read the server's response message. The pipe client must specify GENERIC_READ | GENERIC_WRITE access when it opens its pipe handle by calling the CreateFile function. Then, the pipe client 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 zero 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 pipe clients, but can also be used by a pipe server.

The following example shows a pipe client using TransactNamedPipe. The example assumes that the pipe client has used CreateFile to connect to the pipe and SetNamedPipeHandleState to set the pipe handle's read mode, as shown in the pipe client example in the preceding topic.

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 pipe client uses CallNamedPipe to combine the CreateFile, WaitNamedPipe (if necessary), TransactNamedPipe, and CloseHandle function calls into a single call. 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 specified 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 Reference

The following elements are used with pipes.

  • Pipe Functions


Pipe Functions

The following functions are used with pipes.

Function | Description
CallNamedPipe | Connects to a message-type pipe, writes to and reads from the pipe, and then closes the pipe.
ConnectNamedPipe | Enables a named pipe server process to wait for a client process to connect to an instance of a named pipe.
CreateNamedPipe | Creates an instance of a named pipe and returns a handle for subsequent pipe operations.
CreatePipe | Creates an anonymous pipe.
DisconnectNamedPipe | Disconnects the server end of a named pipe instance from a client process.
GetNamedPipeHandleState | Retrieves information about a specified named pipe.
GetNamedPipeInfo | Retrieves information about the specified named pipe.
PeekNamedPipe | Copies data from a named or anonymous pipe into a buffer without removing it from the pipe.
SetNamedPipeHandleState | Sets the read mode and the blocking mode of the specified named pipe.
TransactNamedPipe | Combines the functions that write a message to and read a message from the specified named pipe into a single network operation.
WaitNamedPipe | Waits until either a time-out interval elapses or an instance of the specified named pipe is available for a connection.


CallNamedPipe

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,  // pipe name
  LPVOID lpInBuffer,        // write buffer
  DWORD nInBufferSize,      // size of write buffer
  LPVOID lpOutBuffer,       // read buffer
  DWORD nOutBufferSize,     // size of read buffer
  LPDWORD lpBytesRead,      // number of bytes read
  DWORD nTimeOut            // time-out value
);

Parameters

lpNamedPipeName
[in] Pointer to a null-terminated string specifying the pipe name.
lpInBuffer
[in] Pointer to the buffer containing the data written to the pipe.
nInBufferSize
[in] Specifies the size, in bytes, of the write buffer.
lpOutBuffer
[out] Pointer to the buffer that receives the data read from the pipe.
nOutBufferSize
[in] Specifies the size, in bytes, of the read buffer.
lpBytesRead
[out] Pointer to a variable that receives the number of bytes read from the pipe.
nTimeOut
[in] 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

For example, see Transactions on Named Pipes.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Pipes Overview, Pipe Functions, CloseHandle, CreateFile, CreateNamedPipe, TransactNamedPipe, WaitNamedPipe


ConnectNamedPipe

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 to named pipe
  LPOVERLAPPED lpOverlapped   // overlapped structure
);

Parameters

hNamedPipe
[in] Handle to the server end of a named pipe instance. This handle is returned by the CreateNamedPipe function.
lpOverlapped
[in] Pointer to an OVERLAPPED structure.

If hNamedPipe was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must not be NULL. It must point to a valid OVERLAPPED structure. If hNamedPipe was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function can incorrectly report that the connect operation is complete.

If hNamedPipe was created with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the OVERLAPPED structure must contain a handle to a manual-reset event object (which the server can create by using the CreateEvent function).

If hNamedPipe was not opened with FILE_FLAG_OVERLAPPED, the function does not return until a client is connected or an error occurs. Successful synchronous operations result in the function returning a nonzero value if a client connects after the function is called.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

If a client connects before the function is called, the function returns zero 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 zero.

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 zero, 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 server process can use any of the wait functions 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 a nonzero value 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 zero. 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 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.

For example, see Multithreaded Pipe Server.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Pipes Overview, Pipe Functions, CallNamedPipe, CreateEvent, CreateFile, CreateNamedPipe, DisconnectNamedPipe, GetOverlappedResult, SetNamedPipeHandleState, SleepEx, OVERLAPPED


CreateNamedPipe

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,                             // pipe name
  DWORD dwOpenMode,                           // pipe open mode
  DWORD dwPipeMode,                           // pipe-specific modes
  DWORD nMaxInstances,                        // maximum number of instances
  DWORD nOutBufferSize,                       // output buffer size
  DWORD nInBufferSize,                        // input buffer size
  DWORD nDefaultTimeOut,                      // time-out interval
  LPSECURITY_ATTRIBUTES lpSecurityAttributes  // SD
);

Parameters

lpName
[in] Pointer 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
[in] Specifies the pipe access mode, the overlapped mode, the write-through mode, and the security access mode of the pipe handle.

CreateNamedPipe fails if dwOpenMode specifies any flags other than those listed in the following tables.

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 SACL. For more information, see Access-Control Lists (ACLs) and SACL Access Right.

dwPipeMode
[in] 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. For more information on asynchronous pipe I/O, see Synchronous and Overlapped Input and Output.

nMaxInstances
[in] 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
[in] 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
[in] 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
[in] 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
[in] Pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new named pipe and determines whether child processes can inherit the returned handle. If lpSecurityAttributes is NULL, the named pipe gets a default security descriptor and the handle cannot be inherited.

Return Values

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 client side of a named pipe starts out in byte mode, even if the server side is in message mode. To avoid problems receiving data, set the client side to message mode as well.

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 pipe server should not perform a blocking read operation until the pipe client has started. Otherwise, a race condition can occur. This typically occurs when initialization code, such as the C run-time, needs to lock and examine inherited handles.

An instance of a named pipe is always deleted when the last handle to the instance of the named pipe is closed.

For example, see Multithreaded Pipe Server.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Pipes Overview, Pipe Functions, ConnectNamedPipe, CreateFile, ReadFile, ReadFileEx, SECURITY_ATTRIBUTES, TransactNamedPipe, WaitNamedPipe, WriteFile, WriteFileEx


CreatePipe

The CreatePipe function creates an anonymous pipe, and returns handles to the read and write ends of the pipe.

BOOL CreatePipe(
  PHANDLE hReadPipe,                       // read handle
  PHANDLE hWritePipe,                      // write handle
  LPSECURITY_ATTRIBUTES lpPipeAttributes,  // security attributes
  DWORD nSize                              // pipe size
);

Parameters

hReadPipe
[out] Pointer to a variable that receives the read handle for the pipe.
hWritePipe
[out] Pointer to a variable that receives the write handle for the pipe.
lpPipeAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpPipeAttributes is NULL, the handle cannot be inherited.

Windows NT/2000: The lpSecurityDescriptor member of the structure specifies a security descriptor for the new pipe. If lpPipeAttributes is NULL, the pipe gets a default security descriptor.

nSize
[in] Specifies the buffer size for the pipe, in bytes. 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

To read from the pipe, a process uses the read handle in a call to the ReadFile function. ReadFile returns when one of the following is true: a write operation completes on the write end of the pipe, the number of bytes requested has been read, or an error occurs.

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.

Windows NT/2000: Anonymous pipes are implemented using a named pipe with a unique name. Therefore, you can often pass a handle to an anonymous pipe to a function that requires a handle to a named pipe.

For example, see Creating a Child Process with Redirected Input and Output.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Pipes Overview, Pipe Functions, ReadFile, SECURITY_ATTRIBUTES, WriteFile


DisconnectNamedPipe

The DisconnectNamedPipe function disconnects the server end of a named pipe instance from a client process.

BOOL DisconnectNamedPipe(
  HANDLE hNamedPipe   // handle to named pipe
);

Parameters

hNamedPipe
[in] Handle to an instance of a named pipe. This handle must be created by the CreateNamedPipe function.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

For example, see Multithreaded Pipe Server.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Pipes Overview, Pipe Functions, CloseHandle, ConnectNamedPipe, CreateNamedPipe, FlushFileBuffers


GetNamedPipeHandleState

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 to named pipe
  LPDWORD lpState,               // pipe state
  LPDWORD lpCurInstances,        // number of pipe instances
  LPDWORD lpMaxCollectionCount,  // maximum collection count
  LPDWORD lpCollectDataTimeout,  // time before transmission
  LPTSTR lpUserName,             // client user name
  DWORD nMaxUserNameSize         // size of user name buffer
);

Parameters

hNamedPipe
[in] Handle to the named pipe for which information is wanted. The handle must have GENERIC_READ access to the named pipe.

Windows NT/2000: This parameter can also be a handle to an anonymous pipe, as returned by the CreatePipe function.

lpState
[out] Pointer to a 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
[out] Pointer to a variable that receives the number of current pipe instances. This parameter can be NULL if this information is not required.
lpMaxCollectionCount
[out] Pointer to a 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
[out] Pointer to a 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
[out] Pointer to a buffer that receives the null-terminated string containing the user name string associated with the client application. The server can only retrieve this information if the client opened the pipe with SECURITY_IMPERSONATION access.

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
[in] Specifies the size, in TCHARs, of the buffer specified by the lpUserName parameter. This parameter is ignored if lpUserName is NULL.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Pipes Overview, Pipe Functions, SetNamedPipeHandleState


GetNamedPipeInfo

The GetNamedPipeInfo function retrieves information about the specified named pipe.

BOOL GetNamedPipeInfo(
  HANDLE hNamedPipe,        // handle to named pipe
  LPDWORD lpFlags,          // pipe type
  LPDWORD lpOutBufferSize,  // size of output buffer
  LPDWORD lpInBufferSize,   // size of input buffer
  LPDWORD lpMaxInstances    // maximum number of pipe instances
);

Parameters

hNamedPipe
[in] Handle to the named pipe instance. The handle must have GENERIC_READ access to the named pipe.

Windows NT/2000: This parameter can also be a handle to an anonymous pipe, as returned by the CreatePipe function.

lpFlags
[in] Pointer to a variable that indicates the type of the named pipe. This parameter can be NULL if this information is not required. Otherwise, use the following values.
Value | Meaning
PIPE_CLIENT_END | The handle refers to the client end of a named pipe instance. This is the default.
PIPE_SERVER_END | 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_BYTE | The named pipe is a byte pipe. This is the default.
PIPE_TYPE_MESSAGE | The named pipe is a message pipe. If this value is not specified, the pipe is a byte pipe.

lpOutBufferSize
[out] Pointer to a 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
[out] Pointer to a 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
[out] Pointer to a 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Pipes Overview, Pipe Functions, CreateNamedPipe, GetNamedPipeHandleState


PeekNamedPipe

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 hNamedPipe,              // handle to pipe
  LPVOID lpBuffer,                // data buffer
  DWORD nBufferSize,              // size of data buffer
  LPDWORD lpBytesRead,            // number of bytes read
  LPDWORD lpTotalBytesAvail,      // number of bytes available
  LPDWORD lpBytesLeftThisMessage  // unread bytes
);

Parameters

hNamedPipe
[in] Handle to 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.
lpBuffer
[out] Pointer to a buffer that receives data read from the pipe. This parameter can be NULL if no data is to be read.
nBufferSize
[in] Specifies the size, in bytes, of the buffer specified by the lpBuffer parameter. This parameter is ignored if lpBuffer is NULL.
lpBytesRead
[out] Pointer to a variable that receives the number of bytes read from the pipe. This parameter can be NULL if no data is to be read.
lpTotalBytesAvail
[out] Pointer to a 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.
lpBytesLeftThisMessage
[out] Pointer to a 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The PeekNamedPipe function is similar to the ReadFile function with the following exceptions:

  • The data is read in the mode specified with CreateNamedPipe. For example, create a pipe with PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE. If you change the mode to PIPE_READMODE_BYTE with SetNamedPipeHandleState, ReadFile will read in byte mode, but PeekNamedPipe will continue to read in message mode.
  • 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 nBufferSize. For a named pipe handle in message-read mode, the function reads the next message in the pipe. If the message is larger than nBufferSize, the function returns TRUE after reading the specified number of bytes. In this situation, lpBytesLeftThisMessage will receive the number of bytes remaining in the message.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Pipes Overview, Pipe Functions, CreateFile, CreateNamedPipe, CreatePipe, ReadFile, WriteFile


SetNamedPipeHandleState

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 to named pipe
  LPDWORD lpMode,                // new pipe mode
  LPDWORD lpMaxCollectionCount,  // maximum collection count
  LPDWORD lpCollectDataTimeout   // time-out value
);

Parameters

hNamedPipe
[in] Handle to 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.

Windows NT/2000: This parameter can also be a handle to an anonymous pipe, as returned by the CreatePipe function.

lpMode
[in] Pointer to a 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. Specify one of the following modes.
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.

lpMaxCollectionCount
[in] Pointer to a 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.
lpCollectDataTimeout
[in] Pointer to a 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 Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

For example, see Named Pipe Client.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Pipes Overview, Pipe Functions, ConnectNamedPipe, CreateFile, CreateNamedPipe, GetNamedPipeHandleState, ReadFile, WriteFile


TransactNamedPipe

The TransactNamedPipe function combines the functions that write a message to and read a message from the specified named pipe into a single network operation.

BOOL TransactNamedPipe(
  HANDLE hNamedPipe,          // handle to named pipe
  LPVOID lpInBuffer,          // write buffer
  DWORD nInBufferSize,        // size of write buffer
  LPVOID lpOutBuffer,         // read buffer
  DWORD nOutBufferSize,       // size of read buffer
  LPDWORD lpBytesRead,        // bytes read
  LPOVERLAPPED lpOverlapped   // overlapped structure
);

Parameters

hNamedPipe
[in] Handle to the named pipe returned by the CreateNamedPipe or CreateFile function.

Windows NT/2000: This parameter can also be a handle to an anonymous pipe, as returned by the CreatePipe function.

lpInBuffer
[in] Pointer to the buffer containing the data written to the pipe.
nInBufferSize
[in] Specifies the size, in bytes, of the write buffer.
lpOutBuffer
[out] Pointer to the buffer that receives the data read from the pipe.
nOutBufferSize
[in] Specifies the size, in bytes, of the read buffer.
lpBytesRead
[out] Pointer to the variable that receives the number of bytes read from the pipe.

If lpOverlapped is NULL, lpBytesRead cannot be NULL.

If lpOverlapped is not NULL, lpBytesRead can be NULL. If this is an overlapped read operation, you can get the number of bytes read by calling GetOverlappedResult. If hNamedPipe is associated with an I/O completion port, you can get the number of bytes read by calling GetQueuedCompletionStatus.

lpOverlapped
[in] Pointer to an OVERLAPPED structure. This structure is required if hNamedPipe was opened with FILE_FLAG_OVERLAPPED.

If hNamedPipe was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must not be NULL. It must point to a valid OVERLAPPED structure. If hNamedPipe was created with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function can incorrectly report that the opeation is complete.

If hNamePipe was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, 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.

If hNamedPipe was not opened with FILE_FLAG_OVERLAPPED, TransactNamedPipe does not return until the operation is complete.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 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. For example, if a client is running on the same machine as the server and uses the \\.\pipe\pipename format to open the pipe, the pipe is opened in byte mode by the named pipe file system (NPFS). If the client uses the form \\server\pipe\pipename, the redirector opens the pipe in message mode. A byte mode pipe handle can be changed to message-read mode with the SetNamedPipeHandleState function.

The function cannot be completed successfully until data is written into the buffer specified by the lpOutBuffer parameter. The lpOverlapped 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 nOutBufferSize 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.

For example, see Transactions on Named Pipes.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Pipes Overview, Pipe Functions, CreateEvent, CreateFile, CreateNamedPipe, GetOverlappedResult, GetQueuedCompletionStatus, PeekNamedPipe, ReadFile, ReadFileEx, SetNamedPipeHandleState, OVERLAPPED


WaitNamedPipe

The WaitNamedPipe function waits until either a time-out interval elapses or an instance of the specified named pipe is available for connection (that is, the pipe's server process has a pending ConnectNamedPipe operation on the pipe).

BOOL WaitNamedPipe(
  LPCTSTR lpNamedPipeName,  // pipe name
  DWORD nTimeOut            // time-out interval
);

Parameters

lpNamedPipeName
[in] Pointer 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

nTimeOut
[in] Specifies the number of milliseconds that the function will wait for an instance of the named pipe to be available. You can used one of the following values 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 Values

If an instance of the pipe is available before the time-out interval elapses, the return value is nonzero.

If an instance of the pipe is not available before the time-out interval elapses, the return value is zero. 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.

For example, see Named Pipe Client.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Pipes Overview, Pipe Functions, CallNamedPipe, ConnectNamedPipe, CreateFile, CreateNamedPipe


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

    Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

    Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

    Remedy: Insert the MSDN Library CD into the CD-ROM drive.