Introduction
In this article we will learn how to add controls to a MessageBox or how to change its button texts. You can use this method to create (full) Multilanguage programs (Just a suggestion!). There are some ways to do this and I chose the hooking method.
Steps of Hooking a MessageBox
To hook a MessageBox:
- Use
SetWindowsHookEx ()
function with WH_CALLWIND
and pass it to a hookproc.
- Declare a hook procedure.
- In the hookproc use the
SetWindowLong ()
function to handle the MessageBox window Creation process (Maybe it is a good name for this).
- Declare a
CALLBACK
function to handle the MessageBox window creation process.
- Pass the
CALLBACK
function as the new long
parameter in the SetWindowLong ()
function.
- And at the end, place your codes in the
CALLBACK
function (codes for window creation).
SetWindowsHookEx () function
This function installs a hook procedure. Using this function you can hook windows events. In other words when you install a hook procedure you tell the system to notify you when the wanted event is called.
As MSDN says: 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.
How to Install a hook procedure using SetWindowsHookEx () function?
g_hHook = SetWindowsHookEx (WH_CALLWNDPROC,
(HOOKPROC)SetHook,
NULL,
GetCurrentThreadId ());
Where g_hHook
is a global variable and the SetHook
is my HookProc;
What is WH_CALLWNDPROC?
Use this parameter to install a hook procedure that monitors messages before the system sends them to the destination window procedure (MSDN).
Declaring a HookProcedure
Use the following declarations in your header file:
LRESULT CALLBACK SetHook(int nCode,WPARAM wParam,LPARAM lParam);
This will declare a hook procedure by name SetHook
. See this code snippet:
LRESULT CALLBACK SetHook(int nCode,WPARAM wParam,LPARAM lParam)
{
if (nCode==HC_ACTION)
{
CWPSTRUCT* pwp = (CWPSTRUCT*)lParam;
if (pwp->message==WM_INITDIALOG)
oldProc=(WNDPROC)SetWindowLong(pwp>hwnd,
GWL_WNDPROC,(LONG)HookWndProc);
}
return CallNextHookEx(g_hHook,nCode,wParam,lParam);
}
This code snippet is my SetHook
procedure.
What is GWL_WNDPROC?
This parameter sets a new address for the window procedure. (I think it is enough).
What is CWPSTRUCT?
This is a structure that contains information about window messages like a handle to that window (hwnd
). We pass a pointer of this structure to use the hwnd
member in the callback function.
And the HookWndProc
is a function that processes the window creation codes.
Handling the window creation process
To do this, you must declare a CALLBACK
function.
LRESULT CALLBACK HookWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
This is my HookWndProc
procedure.
LRESULT CALLBACK HookWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
LRESULT rc = CallWindowProc( oldProc, hWnd, uMsg, wParam, lParam );
if (uMsg==WM_INITDIALOG)
{
if (m_hIcon)
SetIcon(hWnd,m_hIcon);
CreateButton(hWnd);
if (m_strCaption)
SetCaption(hWnd);
}
if (uMsg==WM_COMMAND&&wParam==IDC_CHECKBOX)
SetOut(wParam);
if (uMsg==WM_NCDESTROY)
UnInstallHook(g_hHook);
return rc;
}
The main operations are done. I mean the hwnd
. After having this hwnd
, we can do everything to the MessageBox window. But don�t forget to call CallWindowProc
function.
What does the CallWindowProc
do?
According to MSDN: The CallWindowProc
function passes message information to the specified window procedure.
I used this function because I didn�t want to paint the MessageBox window myself and I wanted only to change some texts. If you want to paint the main window, I think you shouldn�t call this function!
For more information about SetWindowsHookEx
, SetWindowLong
and CallWindowProc
use MSDN Library. (I think it is the best reference to revert).
And at last I want to warn you: Call the CallNextHookEx ()
function because if you don�t do this, other applications that may have installed a hook chain will not receive the hook information and I know you don�t want it.
And like always, according to MSDN that says: 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.
Last Words
First of all, I want to thanks to Mr. Nicolas Bonamy. His article helped me a lot.
There is a demo app which if you want, can download. In that project I have a class that contains some codes for adding a CheckBox to the MessageBox and to change the text of buttons and some functions to place the controls in a right and good place.
And I want to say that my English is not very well and it is a reason to write MSDN Library definitions for some functions (Excuse me for bad grammar).
And at last I suggest you to use Visual Assist X because it is a helpful plug-in for Visual Studio.
Please vote this article if you find it interesting and informative. Opinions and comments are welcome.
G.K.Z - King Zoser.