The standard BCB program uses Application-> Run () to enter the message loop. In the ProcessMessage method of the Application, the PeekMessage method is used to extract messages from the message queue, and remove the message from the message queue. Then the ProcessMessage method checks whether the Application-> OnMessage method exists. If yes, transfer it to this method to process the message. Then, the processed messages are distributed to each object in the program. At this point, the WndProc method receives the message and processes it. If there is any way to handle Dispatch that cannot be handled by the heavy load. If not, submit it to the Dispatch method of the parent class for processing. Finally, the Dispatch method actually transfers the message to the DefaultHandler method for processing. (Hey, actually, you can reload the DefaultHandler method to process messages, but it's too late. I don't think anyone is willing to process the last message ).
1. Application of TApplication's OnMessage event
In an application developed by C ++ Builder, an OnMessage event is triggered when any form receives a Windows message. Therefore, you can capture any Windows messages sent to the program through the OnMessage event of the corresponding TApplication object.
The OnMessage event processing function prototype is as follows:
Typedef void _ fastcall (_ closure * TMessageEvent) (tagMsg & Msg, bool & Handled );
This processing function has two parameters. The Msg parameter indicates the intercepted message, and the Handled parameter indicates whether the message has been processed. In the program, you can set the Handled parameter to true to avoid subsequent processes processing the message. Otherwise, set Handled to false to allow subsequent processes to continue to process the message.
It should be noted that the OnMessage event only accepts messages sent to the message queue, and messages sent directly to the window function through the API function SendMessage () will not be intercepted. In addition, when the program runs, the OnMessage event may be triggered frequently, so the execution time of the event processing function code will directly affect the running efficiency of the entire program.
2. intercept messages using message ing
C ++ Builder VCL provides a processing mechanism for most Windows messages, which is sufficient for general applications. However, VCL is not all-encompassing. In some cases, when the program needs to process Windows messages that are not processed by VCL, or when the program needs to block certain messages, the programmer needs to capture Windows messages by himself.
Therefore, C ++ Builder provides a message ing mechanism to associate a specific Windows message with the corresponding processing function through the message ing program, when this message is captured in the window, the corresponding processing function is automatically called.
There are several steps to use message ing:
(1) In the message ing table, the processing permission of some messages is handed over to the custom message processing function.
Such a message ing list should be located in the definition of a component class. It starts with a BEGIN_MESSAGE_MAP macro without parameters and ends with an END_MESSAGE_MAP macro. The unique parameter of the END_MESSAGE_MAP macro should be the name of the parent class of the component. Generally, this so-called parent class refers to TForm. Insert one or more MESSAGE_HANDLER macros between the macro BEGIN_MESSAGE_MAP and END_MESSAGE_MAP.
The MESSAGE_HANDLER macro associates a message handle with a message processing function.
The MESSAGE_HANDLER macro has three parameters: Windows message name, message struct name, and corresponding message processing function name. The message struct name can be either a common message struct TMessage or a specific message struct, such as TWMMouse.
When using message ing, pay attention to the following two points:
A. a window class definition can have only one message ing table.
B. The message ing must be placed behind the declaration of all message processing functions referenced by the message ing function.
(2) Declare the message processing function in the window class
The message processing function names and parameters must be consistent with the corresponding MESSAGE_HANDLER macro.
The declaration of a typical message processing function is as follows:
Void _ fastcall Message processing function name (Message struct name & Message );
For example:
Void _ fastcall WMNchitTest (TMessage & message );
(3) message processing functions
The compilation of Message processing functions is not much different from that of common functions. The only difference is that a statement TForm: Dispatch (& Message) must be added at the end of the function ), to complete VCL's default message processing. Without this sentence, the message will be completely intercepted; in some cases, VCL may fail to work because the message is not received.
3. Reload the WndProc () function
In some cases, the program needs to capture or shield certain messages. In this case, you can use the message ing method described earlier. Of course, this method is not unique, and can also be implemented by reloading the window function WndProc. Because the system will call the window function WndProc () before calling the Dispatch () function to send messages, you can use the overload function WndProc () to obtain an opportunity to filter messages before dispatching messages.
The prototype of the window function for message processing is as follows:
Virtual void _ fastcall WndProc (TMessage & Message );
Example: (for details, see the NowCan example)
Void _ fastcall TForm1: WndProc (TMessage & Message)
{
PCOPYDATASTRUCT pMyCDS;
If (Message. Msg = g_MyMsg)
{
ShowMessage ("received registration Message, wParam =" + IntToStr (Message. WParam) + "lParam =" + IntToStr (Message. LParam ));
Message. Result = 0; // The Message processing Result, of course, is meaningless in this example.
}
Else if (Message. Msg = g_MyMsg1)
{
Application-> MessageBoxA (char *) Message. LParam, "receiving the sender's string", MB_ OK );
}
Else if (Message. Msg = WM_COPYDATA)
{
PMyCDS = (PCOPYDATASTRUCT) Message. LParam;
Application-> MessageBoxA (char *) pMyCDS-> lpData, "receiving the sender's string", MB_ OK );
}
TForm: WndProc (Message); // other messages are transmitted.
}
At first glance, this is similar to the method for reloading Dispatch. But there is actually a difference. The difference lies in the order of order. The message is first sent to WndProc for processing, and then the Dispatch method is called. In this way, the overloaded WndProc method can obtain and process messages a little earlier than the overloaded Dispatch method.
4. Application-> HookMainWindow Method
If you plan to use Application-> OnMessage to capture all messages sent to your Application, you may be disappointed. It cannot capture messages sent directly to the window using SendMessage because it does not pass the message queue. You may say that I can directly reload the WndProc method of TApplication. No. Because the WndProc method of TApplication is declared as static by Borland, it cannot be overloaded. Obviously, this is probably Because Borland is concerned about its side effects. So how should we be good? View the pascal source code of WndProc of TApplication. You can see:
Procedure TApplication. WndProc (var Message: TMessage );
... // Saves space. The Code irrelevant to the topic is skipped here.
Begin
Try
Message. Result: = 0;
For I: = 0 to FWindowHooks. Count-1 do
If TWindowHook (FWindowHooks [I] ^) (Message) then Exit;
... // Saves space. The Code irrelevant to the topic is skipped here.
The WndProc method first calls the custom message processing method of the HookMainWindow hook, and then calls the default process to process the message. In this way, you can use HookMainWindow to indirectly add your own message processing method to WndProc. It is useful to use this method to respond to the message sent by SendMessage. Finally, we will remind you that after using the HookMainWindow Hook, you must call the UnhookMainWindow to uninstall the hook program. Here is an example:
Void _ fastcall TForm1: FormCreate (TObject * Sender)
{
Application-> HookMainWindow (AppHookFunc );
}
//---------------------------------------------------------------------------
Bool _ fastcall tform1: apphookfunc (tmessage & message)
{
Bool handled;
Switch (message. msg)
{
Case wm_close:
Mryes = messagedlg ("really close ?? ", Mtwarning, tmsgdlgbuttons () <mbyes Break;
}
Return handled;
}
//---------------------------------------------------------------------------
Void _ fastcall tform1: formdestroy (tobject * sender)
{
Application-> unhookmainwindow (apphookfunc );
}
//---------------------------------------------------------------------------
Void _ fastcall tform1: button1click (tobject * sender)
{
SendMessage (Application-> Handle, WM_CLOSE, 0, 0 );
}
//---------------------------------------------------------------------------
5. Send messages by yourself
Applications can also send messages between Windows or components like Windows systems. C ++ Builder provides several ways to do this: Use the TControl: Perform () function or the API functions SendMessage () and PostMessage () to send messages to a specific form, or use the TWinControl function:: Broadcast () and API functions BroadcastSystemMessage () Broadcast messages.
The Perform () function is used to pass the specified message to the WndProc process of TControl. It is applicable to all objects derived from the TControl class. The Perform () prototype is as follows:
Int _ fastcall Perform (unsigned Msg, int WParam, int LParam );
It is not returned until the message is processed.
Using the Perform () function between different forms and controls of the same application is very convenient. However, this function is a member function of the TControl class. That is to say, when using it, the program must know the instance of the control that receives the message. In many cases, the program does not know the instance of the form that receives the message but the handle of the form. For example, sending messages between forms of different applications is the case. In this case, the function Perform () is obviously unavailable and should be replaced by the SendMessage () and PostMessage () functions ().
The SendMessage () and PostMessage () functions are basically the same. They can be used to send messages to a specific window handle. The main difference is that the SendMessage () function directly sends a message to the window function and returns it only after the message is processed. The PostMessage () function only sends the message to the message queue, then return immediately.
The prototype Declaration of the two functions is as follows:
LRESULT SendMessage (HWND hWnd, UINRT Msg, WPARAM, wParam, LPARAM, lParam );
BOOL PostMessage (HWND hWnd, UINT Msg, WPARAM, wParam, LPARAM, lParam );
As you can see, these two function parameters are very similar to the function Perform (), but an hWnd parameter is added to indicate the handle of the target window.
Broadcast () and BroadcastSystemMessage ()
The function Broadcast () applies to all objects derived from the TWinControl class. It can Broadcast messages to all child controls on the form. The function prototype is as follows:
Void _ fastcall Broadcast (void * Message );
We can see that this function has only one Message parameter, which points to the Message struct of the broadcast TMessage type.
The function Broadcast () can only Broadcast messages to all child controls on the specified form in the C ++ Builder application. to Broadcast messages to other applications or forms in the system, the function Broadcast () you can't do anything about it. You can use the API function BroadcastSystemMessage () to broadcast messages to any application or component. The function prototype is as follows:
Long BroadcastSystemMessage (
DWORD dwFlags,
LPWORD lpdwRecipients,
UINT uiMessage,
WPAREM wParam,
LPARAM lParam
);