- FormatMessageA function (winbase.h)
- Syntax
- Parameters
- Return value
- Remarks
- Security Remarks
- Examples
- About Messages and Message Queues
- Windows Messages
- Message Types
- System-Defined Messages
- Application-Defined Messages
- Message Routing
- Queued Messages
- Nonqueued Messages
- Message Handling
- Message Loop
- Window Procedure
- Message Filtering
- Posting and Sending Messages
- Posting Messages
- Sending Messages
- Message Deadlocks
- Broadcasting Messages
- Query Messages
FormatMessageA function (winbase.h)
Formats a message string. The function requires a message definition as input. The message definition can come from a buffer passed into the function. It can come from a message table resource in an already-loaded module. Or the caller can ask the function to search the system’s message table resource(s) for the message definition. The function finds the message definition in a message table resource based on a message identifier and a language identifier. The function copies the formatted message text to an output buffer, processing any embedded insert sequences if requested.
Syntax
Parameters
The formatting options, and how to interpret the lpSource parameter. The low-order byte of dwFlags specifies how the function handles line breaks in the output buffer. The low-order byte can also specify the maximum width of a formatted output line.
This parameter can be one or more of the following values.
Value | Meaning |
---|---|
FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 | The function allocates a buffer large enough to hold the formatted message, and places a pointer to the allocated buffer at the address specified by lpBuffer. The lpBuffer parameter is a pointer to an LPTSTR; you must cast the pointer to an LPTSTR (for example, (LPTSTR)&lpBuffer ). The nSize parameter specifies the minimum number of TCHARs to allocate for an output message buffer. The caller should use the LocalFree function to free the buffer when it is no longer needed. If the length of the formatted message exceeds 128K bytes, then FormatMessage will fail and a subsequent call to GetLastError will return ERROR_MORE_DATA. In previous versions of Windows, this value was not available for use when compiling Windows Store apps. As of WindowsВ 10 this value can be used. Windows ServerВ 2003 and WindowsВ XP:В В If the length of the formatted message exceeds 128K bytes, then FormatMessage will not automatically fail with an error of ERROR_MORE_DATA. |
FORMAT_MESSAGE_ARGUMENT_ARRAY 0x00002000 | The Arguments parameter is not a va_list structure, but is a pointer to an array of values that represent the arguments. This flag cannot be used with 64-bit integer values. If you are using a 64-bit integer, you must use the va_list structure. |
FORMAT_MESSAGE_FROM_HMODULE 0x00000800 | The lpSource parameter is a module handle containing the message-table resource(s) to search. If this lpSource handle is NULL, the current process’s application image file will be searched. This flag cannot be used with FORMAT_MESSAGE_FROM_STRING. If the module has no message table resource, the function fails with ERROR_RESOURCE_TYPE_NOT_FOUND. |
FORMAT_MESSAGE_FROM_STRING 0x00000400 | The lpSource parameter is a pointer to a null-terminated string that contains a message definition. The message definition may contain insert sequences, just as the message text in a message table resource may. This flag cannot be used with FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_FROM_SYSTEM. |
FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 | The function should search the system message-table resource(s) for the requested message. If this flag is specified with FORMAT_MESSAGE_FROM_HMODULE, the function searches the system message table if the message is not found in the module specified by lpSource. This flag cannot be used with FORMAT_MESSAGE_FROM_STRING. If this flag is specified, an application can pass the result of the GetLastError function to retrieve the message text for a system-defined error. |
FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 | Insert sequences in the message definition such as %1 are to be ignored and passed through to the output buffer unchanged. This flag is useful for fetching a message for later formatting. If this flag is set, the Arguments parameter is ignored. |
В
The low-order byte of dwFlags can specify the maximum width of a formatted output line. The following are possible values of the low-order byte.
Value | Meaning |
---|---|
0 | There are no output line width restrictions. The function stores line breaks that are in the message definition text into the output buffer. |
FORMAT_MESSAGE_MAX_WIDTH_MASK 0x000000FF | The function ignores regular line breaks in the message definition text. The function stores hard-coded line breaks in the message definition text into the output buffer. The function generates no new line breaks. |
В
If the low-order byte is a nonzero value other than FORMAT_MESSAGE_MAX_WIDTH_MASK, it specifies the maximum number of characters in an output line. The function ignores regular line breaks in the message definition text. The function never splits a string delimited by white space across a line break. The function stores hard-coded line breaks in the message definition text into the output buffer. Hard-coded line breaks are coded with the %n escape sequence.
The location of the message definition. The type of this parameter depends upon the settings in the dwFlags parameter.
dwFlags Setting | Meaning |
---|---|
FORMAT_MESSAGE_FROM_HMODULE 0x00000800 | A handle to the module that contains the message table to search. |
FORMAT_MESSAGE_FROM_STRING 0x00000400 | Pointer to a string that consists of unformatted message text. It will be scanned for inserts and formatted accordingly. |
В
If neither of these flags is set in dwFlags, then lpSource is ignored.
The message identifier for the requested message. This parameter is ignored if dwFlags includes FORMAT_MESSAGE_FROM_STRING.
The language identifier for the requested message. This parameter is ignored if dwFlags includes FORMAT_MESSAGE_FROM_STRING.
If you pass a specific LANGID in this parameter, FormatMessage will return a message for that LANGID only. If the function cannot find a message for that LANGID, it sets Last-Error to ERROR_RESOURCE_LANG_NOT_FOUND. If you pass in zero, FormatMessage looks for a message for LANGIDs in the following order:
- Language neutral
- Thread LANGID, based on the thread’s locale value
- User default LANGID, based on the user’s default locale value
- System default LANGID, based on the system default locale value
- US English
If FormatMessage does not locate a message for any of the preceding LANGIDs, it returns any language message string that is present. If that fails, it returns ERROR_RESOURCE_LANG_NOT_FOUND.
A pointer to a buffer that receives the null-terminated string that specifies the formatted message. If dwFlags includes FORMAT_MESSAGE_ALLOCATE_BUFFER, the function allocates a buffer using the LocalAlloc function, and places the pointer to the buffer at the address specified in lpBuffer.
This buffer cannot be larger than 64K bytes.
If the FORMAT_MESSAGE_ALLOCATE_BUFFER flag is not set, this parameter specifies the size of the output buffer, in TCHARs. If FORMAT_MESSAGE_ALLOCATE_BUFFER is set, this parameter specifies the minimum number of TCHARs to allocate for an output buffer.
The output buffer cannot be larger than 64K bytes.
An array of values that are used as insert values in the formatted message. A %1 in the format string indicates the first value in the Arguments array; a %2 indicates the second argument; and so on.
The interpretation of each value depends on the formatting information associated with the insert in the message definition. The default is to treat each value as a pointer to a null-terminated string.
By default, the Arguments parameter is of type va_list*, which is a language- and implementation-specific data type for describing a variable number of arguments. The state of the va_list argument is undefined upon return from the function. To use the va_list again, destroy the variable argument list pointer using va_end and reinitialize it with va_start.
If you do not have a pointer of type va_list*, then specify the FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array of DWORD_PTR values; those values are input to the message formatted as the insert values. Each insert must have a corresponding element in the array.
Return value
If the function succeeds, the return value is the number of TCHARs stored in the output buffer, excluding the terminating null character.
If the function fails, the return value is zero. To get extended error information, call GetLastError.
Remarks
Within the message text, several escape sequences are supported for dynamically formatting the message. These escape sequences and their meanings are shown in the following tables. All escape sequences start with the percent character (%).
Escape sequence | Meaning | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
%0 | Terminates a message text line without a trailing new line character. This escape sequence can be used to build up long lines or to terminate the message itself without a trailing new line character. It is useful for prompt messages. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
%n!format string! | Identifies an insert sequence. The value of n can be in the range from 1 through 99. The format string (which must be surrounded by exclamation marks) is optional and defaults to !s! if not specified. For more information, see Format Specification Fields. The format string can include a width and precision specifier for strings and a width specifier for integers. Use an asterisk () to specify the width and precision. For example, %1!.*s! or %1!*u!. If you do not use the width and precision specifiers, the insert numbers correspond directly to the input arguments. For example, if the source string is «%1 %2 %1» and the input arguments are «Bill» and «Bob», the formatted output string is «Bill Bob Bill». However, if you use a width and precision specifier, the insert numbers do not correspond directly to the input arguments. For example, the insert numbers for the previous example could change to «%1!*.*s! %4 %5!*s!». The insert numbers depend on whether you use an arguments array (FORMAT_MESSAGE_ARGUMENT_ARRAY) or a va_list. For an arguments array, the next insert number is n+2 if the previous format string contained one asterisk and is n+3 if two asterisks were specified. For a va_list, the next insert number is n+1 if the previous format string contained one asterisk and is n+2 if two asterisks were specified. If you want to repeat «Bill», as in the previous example, the arguments must include «Bill» twice. For example, if the source string is «%1!*.*s! %4 %5!*s!», the arguments could be, 4, 2, Bill, Bob, 6, Bill (if using the FORMAT_MESSAGE_ARGUMENT_ARRAY flag). The formatted string would then be «В В Bi Bob В В Bill». Repeating insert numbers when the source string contains width and precision specifiers may not yield the intended results. If you replaced %5 with %1, the function would try to print a string at address 6 (likely resulting in an access violation). Floating-point format specifiers—e, E, f, and g—are not supported. The workaround is to use the StringCchPrintf function to format the floating-point number into a temporary buffer, then use that buffer as the insert string. Inserts that use the I64 prefix are treated as two 32-bit arguments. They must be used before subsequent arguments are used. Note that it may be easier for you to use StringCchPrintf instead of this prefix. Any other nondigit character following a percent character is formatted in the output message without the percent character. Following are some examples.
В Security RemarksExamplesThe FormatMessage function can be used to obtain error message strings for the system error codes returned by GetLastError. For an example, see Retrieving the Last-Error Code. The following example shows how to implement the previous example using va_list. The winbase.h header defines FormatMessage as an alias which automatically selects the ANSI or Unicode version of this function based on the definition of the UNICODE preprocessor constant. Mixing usage of the encoding-neutral alias with code that not encoding-neutral can lead to mismatches that result in compilation or runtime errors. For more information, see Conventions for Function Prototypes. About Messages and Message QueuesUnlike MS-DOS-based applications, Windows-based applications are event-driven. They do not make explicit function calls (such as C run-time library calls) to obtain input. Instead, they wait for the system to pass input to them. The system passes all input for an application to the various windows in the application. Each window has a function, called a window procedure, that the system calls whenever it has input for the window. The window procedure processes the input and returns control to the system. For more information about window procedures, see Window Procedures. If a top-level window stops responding to messages for more than several seconds, the system considers the window to be not responding. In this case, the system hides the window and replaces it with a ghost window that has the same Z order, location, size, and visual attributes. This allows the user to move it, resize it, or even close the application. However, these are the only actions available because the application is actually not responding. When in the debugger mode, the system does not generate a ghost window. This section discusses the following topics: Windows MessagesThe system passes input to a window procedure in the form of a message. Messages are generated by both the system and applications. The system generates a message at each input event—for example, when the user types, moves the mouse, or clicks a control such as a scroll bar. The system also generates messages in response to changes in the system brought about by an application, such as when an application changes the pool of system font resources or resizes one of its windows. An application can generate messages to direct its own windows to perform tasks or to communicate with windows in other applications. The system sends a message to a window procedure with a set of four parameters: a window handle, a message identifier, and two values called message parameters. The window handle identifies the window for which the message is intended. The system uses it to determine which window procedure should receive the message. A message identifier is a named constant that identifies the purpose of a message. When a window procedure receives a message, it uses a message identifier to determine how to process the message. For example, the message identifier WM_PAINT tells the window procedure that the window’s client area has changed and must be repainted. Message parameters specify data or the location of data used by a window procedure when processing a message. The meaning and value of the message parameters depend on the message. A message parameter can contain an integer, packed bit flags, a pointer to a structure containing additional data, and so on. When a message does not use message parameters, they are typically set to NULL. A window procedure must check the message identifier to determine how to interpret the message parameters. Message TypesThis section describes the two types of messages: System-Defined MessagesThe system sends or posts a system-defined message when it communicates with an application. It uses these messages to control the operations of applications and to provide input and other information for applications to process. An application can also send or post system-defined messages. Applications generally use these messages to control the operation of control windows created by using preregistered window classes. Each system-defined message has a unique message identifier and a corresponding symbolic constant (defined in the software development kit (SDK) header files) that states the purpose of the message. For example, the WM_PAINT constant requests that a window paint its contents. Symbolic constants specify the category to which system-defined messages belong. The prefix of the constant identifies the type of window that can interpret and process the message. Following are the prefixes and their related message categories.
General window messages cover a wide range of information and requests, including messages for mouse and keyboard input, menu and dialog box input, window creation and management, and Dynamic Data Exchange (DDE). Application-Defined MessagesAn application can create messages to be used by its own windows or to communicate with windows in other processes. If an application creates its own messages, the window procedure that receives them must interpret the messages and provide appropriate processing. Message-identifier values are used as follows:
Message RoutingThe system uses two methods to route messages to a window procedure: posting messages to a first-in, first-out queue called a message queue, a system-defined memory object that temporarily stores messages, and sending messages directly to a window procedure. A messages that is posted to a message queue is called a queued message. These are primarily the result of user input entered through the mouse or keyboard, such as WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR messages. Other queued messages include the timer, paint, and quit messages: WM_TIMER, WM_PAINT, and WM_QUIT. Most other messages, which are sent directly to a window procedure, are called nonqueued messages. Queued MessagesThe system can display any number of windows at a time. To route mouse and keyboard input to the appropriate window, the system uses message queues. The system maintains a single system message queue and one thread-specific message queue for each GUI thread. To avoid the overhead of creating a message queue for non–GUI threads, all threads are created initially without a message queue. The system creates a thread-specific message queue only when the thread makes its first call to one of the specific user functions; no GUI function calls result in the creation of a message queue. Whenever the user moves the mouse, clicks the mouse buttons, or types on the keyboard, the device driver for the mouse or keyboard converts the input into messages and places them in the system message queue. The system removes the messages, one at a time, from the system message queue, examines them to determine the destination window, and then posts them to the message queue of the thread that created the destination window. A thread’s message queue receives all mouse and keyboard messages for the windows created by the thread. The thread removes messages from its queue and directs the system to send them to the appropriate window procedure for processing. With the exception of the WM_PAINT message, the WM_TIMER message, and the WM_QUIT message, the system always posts messages at the end of a message queue. This ensures that a window receives its input messages in the proper first in, first out (FIFO) sequence. The WM_PAINT message, the WM_TIMER message, and the WM_QUIT message, however, are kept in the queue and are forwarded to the window procedure only when the queue contains no other messages. In addition, multiple WM_PAINT messages for the same window are combined into a single WM_PAINT message, consolidating all invalid parts of the client area into a single area. Combining WM_PAINT messages reduces the number of times a window must redraw the contents of its client area. The system posts a message to a thread’s message queue by filling an MSG structure and then copying it to the message queue. Information in MSG includes: the handle of the window for which the message is intended, the message identifier, the two message parameters, the time the message was posted, and the mouse cursor position. A thread can post a message to its own message queue or to the queue of another thread by using the PostMessage or PostThreadMessage function. An application can remove a message from its queue by using the GetMessage function. To examine a message without removing it from its queue, an application can use the PeekMessage function. This function fills MSG with information about the message. After removing a message from its queue, an application can use the DispatchMessage function to direct the system to send the message to a window procedure for processing. DispatchMessage takes a pointer to MSG that was filled by a previous call to the GetMessage or PeekMessage function. DispatchMessage passes the window handle, the message identifier, and the two message parameters to the window procedure, but it does not pass the time the message was posted or mouse cursor position. An application can retrieve this information by calling the GetMessageTime and GetMessagePos functions while processing a message. A thread can use the WaitMessage function to yield control to other threads when it has no messages in its message queue. The function suspends the thread and does not return until a new message is placed in the thread’s message queue. You can call the SetMessageExtraInfo function to associate a value with the current thread’s message queue. Then call the GetMessageExtraInfo function to get the value associated with the last message retrieved by the GetMessage or PeekMessage function. Nonqueued MessagesNonqueued messages are sent immediately to the destination window procedure, bypassing the system message queue and thread message queue. The system typically sends nonqueued messages to notify a window of events that affect it. For example, when the user activates a new application window, the system sends the window a series of messages, including WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR. These messages notify the window that it has been activated, that keyboard input is being directed to the window, and that the mouse cursor has been moved within the borders of the window. Nonqueued messages can also result when an application calls certain system functions. For example, the system sends the WM_WINDOWPOSCHANGED message after an application uses the SetWindowPos function to move a window. Message HandlingAn application must remove and process messages posted to the message queues of its threads. A single-threaded application usually uses a message loop in its WinMain function to remove and send messages to the appropriate window procedures for processing. Applications with multiple threads can include a message loop in each thread that creates a window. The following sections describe how a message loop works and explain the role of a window procedure: Message LoopA simple message loop consists of one function call to each of these three functions: GetMessage, TranslateMessage, and DispatchMessage. Note that if there is an error, GetMessage returns –1, thus the need for the special testing. The GetMessage function retrieves a message from the queue and copies it to a structure of type MSG. It returns a nonzero value, unless it encounters the WM_QUIT message, in which case it returns FALSE and ends the loop. In a single-threaded application, ending the message loop is often the first step in closing the application. An application can end its own loop by using the PostQuitMessage function, typically in response to the WM_DESTROY message in the window procedure of the application’s main window. If you specify a window handle as the second parameter of GetMessage, only messages for the specified window are retrieved from the queue. GetMessage can also filter messages in the queue, retrieving only those messages that fall within a specified range. For more information about filtering messages, see Message Filtering. A thread’s message loop must include TranslateMessage if the thread is to receive character input from the keyboard. The system generates virtual-key messages (WM_KEYDOWN and WM_KEYUP) each time the user presses a key. A virtual-key message contains a virtual-key code that identifies which key was pressed, but not its character value. To retrieve this value, the message loop must contain TranslateMessage, which translates the virtual-key message into a character message (WM_CHAR) and places it back into the application message queue. The character message can then be removed upon a subsequent iteration of the message loop and dispatched to a window procedure. The DispatchMessage function sends a message to the window procedure associated with the window handle specified in the MSG structure. If the window handle is HWND_TOPMOST, DispatchMessage sends the message to the window procedures of all top-level windows in the system. If the window handle is NULL, DispatchMessage does nothing with the message. An application’s main thread starts its message loop after initializing the application and creating at least one window. After it is started, the message loop continues to retrieve messages from the thread’s message queue and to dispatch them to the appropriate windows. The message loop ends when the GetMessage function removes the WM_QUIT message from the message queue. Only one message loop is needed for a message queue, even if an application contains many windows. DispatchMessage always dispatches the message to the proper window; this is because each message in the queue is an MSG structure that contains the handle of the window to which the message belongs. You can modify a message loop in a variety of ways. For example, you can retrieve messages from the queue without dispatching them to a window. This is useful for applications that post messages not specifying a window. You can also direct GetMessage to search for specific messages, leaving other messages in the queue. This is useful if you must temporarily bypass the usual FIFO order of the message queue. An application that uses accelerator keys must be able to translate keyboard messages into command messages. To do this, the application’s message loop must include a call to the TranslateAccelerator function. For more information about accelerator keys, see Keyboard Accelerators. If a thread uses a modeless dialog box, the message loop must include the IsDialogMessage function so that the dialog box can receive keyboard input. Window ProcedureA window procedure is a function that receives and processes all messages sent to the window. Every window class has a window procedure, and every window created with that class uses that same window procedure to respond to messages. The system sends a message to a window procedure by passing the message data as arguments to the procedure. The window procedure then performs an appropriate action for the message; it checks the message identifier and, while processing the message, uses the information specified by the message parameters. A window procedure does not usually ignore a message. If it does not process a message, it must send the message back to the system for default processing. The window procedure does this by calling the DefWindowProc function, which performs a default action and returns a message result. The window procedure must then return this value as its own message result. Most window procedures process just a few messages and pass the others on to the system by calling DefWindowProc. Because a window procedure is shared by all windows belonging to the same class, it can process messages for several different windows. To identify the specific window affected by the message, a window procedure can examine the window handle passed with a message. For more information about window procedures, see Window Procedures. Message FilteringAn application can choose specific messages to retrieve from the message queue (while ignoring other messages) by using the GetMessage or PeekMessage function to specify a message filter. The filter is a range of message identifiers (specified by a first and last identifier), a window handle, or both. GetMessage and PeekMessage use a message filter to select which messages to retrieve from the queue. Message filtering is useful if an application must search the message queue for messages that have arrived later in the queue. It is also useful if an application must process input (hardware) messages before processing posted messages. The WM_KEYFIRST and WM_KEYLAST constants can be used as filter values to retrieve all keyboard messages; the WM_MOUSEFIRST and WM_MOUSELAST constants can be used to retrieve all mouse messages. Any application that filters messages must ensure that a message satisfying the message filter can be posted. For example, if an application filters for a WM_CHAR message in a window that does not receive keyboard input, the GetMessage function does not return. This effectively «hangs» the application. Posting and Sending MessagesAny application can post and send messages. Like the system, an application posts a message by copying it to a message queue and sends a message by passing the message data as arguments to a window procedure. To post messages, an application uses the PostMessage function. An application can send a message by calling the SendMessage, BroadcastSystemMessage, SendMessageCallback, SendMessageTimeout, SendNotifyMessage, or SendDlgItemMessage function. Posting MessagesAn application typically posts a message to notify a specific window to perform a task. PostMessage creates an MSG structure for the message and copies the message to the message queue. The application’s message loop eventually retrieves the message and dispatches it to the appropriate window procedure. An application can post a message without specifying a window. If the application supplies a NULL window handle when calling PostMessage, the message is posted to the queue associated with the current thread. Because no window handle is specified, the application must process the message in the message loop. This is one way to create a message that applies to the entire application, instead of to a specific window. Occasionally, you may want to post a message to all top-level windows in the system. An application can post a message to all top-level windows by calling PostMessage and specifying HWND_TOPMOST in the hwnd parameter. A common programming error is to assume that the PostMessage function always posts a message. This is not true when the message queue is full. An application should check the return value of the PostMessage function to determine whether the message has been posted and, if it has not been, repost it. Sending MessagesAn application typically sends a message to notify a window procedure to perform a task immediately. The SendMessage function sends the message to the window procedure corresponding to the given window. The function waits until the window procedure completes processing and then returns the message result. Parent and child windows often communicate by sending messages to each other. For example, a parent window that has an edit control as its child window can set the text of the control by sending a message to it. The control can notify the parent window of changes to the text that are carried out by the user by sending messages back to the parent. The SendMessageCallback function also sends a message to the window procedure corresponding to the given window. However, this function returns immediately. After the window procedure processes the message, the system calls the specified callback function. For more information about the callback function, see the SendAsyncProc function. Occasionally, you may want to send a message to all top-level windows in the system. For example, if the application changes the system time, it must notify all top-level windows about the change by sending a WM_TIMECHANGE message. An application can send a message to all top-level windows by calling SendMessage and specifying HWND_TOPMOST in the hwnd parameter. You can also broadcast a message to all applications by calling the BroadcastSystemMessage function and specifying BSM_APPLICATIONS in the lpdwRecipients parameter. By using the InSendMessage or InSendMessageEx function, a window procedure can determine whether it is processing a message sent by another thread. This capability is useful when message processing depends on the origin of the message. Message DeadlocksA thread that calls the SendMessage function to send a message to another thread cannot continue executing until the window procedure that receives the message returns. If the receiving thread yields control while processing the message, the sending thread cannot continue executing, because it is waiting for SendMessage to return. If the receiving thread is attached to the same queue as the sender, it can cause an application deadlock to occur. (Note that journal hooks attach threads to the same queue.) Note that the receiving thread need not yield control explicitly; calling any of the following functions can cause a thread to yield control implicitly. To avoid potential deadlocks in your application, consider using the SendNotifyMessage or SendMessageTimeout functions. Otherwise, a window procedure can determine whether a message it has received was sent by another thread by calling the InSendMessage or InSendMessageEx function. Before calling any of the functions in the preceding list while processing a message, the window procedure should first call InSendMessage or InSendMessageEx. If this function returns TRUE, the window procedure must call the ReplyMessage function before any function that causes the thread to yield control. Broadcasting MessagesEach message consists of a message identifier and two parameters, wParam and lParam. The message identifier is a unique value that specifies the message purpose. The parameters provide additional information that is message-specific, but the wParam parameter is generally a type value that provides more information about the message. A message broadcast is simply the sending of a message to multiple recipients in the system. To broadcast a message from an application, use the BroadcastSystemMessage function, specifying the recipients of the message. Rather than specify individual recipients, you must specify one or more types of recipients. These types are applications, installable drivers, network drivers, and system-level device drivers. The system sends broadcast messages to all members of each specified type. The system typically broadcasts messages in response to changes that take place within system-level device drivers or related components. The driver or related component broadcasts the message to applications and other components to notify them of the change. For example, the component responsible for disk drives broadcasts a message whenever the device driver for the floppy disk drive detects a change of media such as when the user inserts a disk in the drive. The system broadcasts messages to recipients in this order: system-level device drivers, network drivers, installable drivers, and applications. This means that system-level device drivers, if chosen as recipients, always get the first opportunity to respond to a message. Within a given recipient type, no driver is guaranteed to receive a given message before any other driver. This means that a message intended for a specific driver must have a globally-unique message identifier so that no other driver unintentionally processes it. Applications receive messages through the window procedure of their top-level windows. Messages are not sent to child windows. Services can receive messages through a window procedure or their service control handlers. System-level device drivers use a related, system-level function to broadcast system messages. Query MessagesYou can create your own custom messages and use them to coordinate activities between your applications and other components in the system. This is especially useful if you have created your own installable drivers or system-level device drivers. Your custom messages can carry information to and from your driver and the applications that use the driver. To poll recipients for permission to carry out a given action, use a query message. You can generate your own query messages by setting the BSF_QUERY value in the dwFlags parameter when calling BroadcastSystemMessage. Each recipient of the query message must return TRUE for the function to send the message to the next recipient. If any recipient returns BROADCAST_QUERY_DENY, the broadcast ends immediately and the function returns a zero. |