[WinAPI] Custom MessageBox

Folosire Windows API in programe C/C++ (forum moderat)
Post Reply
User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

[WinAPI] Custom MessageBox

Post by Ovidiu Cucu » 15 Oct 2007, 21:46

Problema
Dupa apelul functiei MessageBox vreau sa-mi apara un dialog cu background-ul schimbat, ca in exemplul din imagine
logo.gif
logo.gif (14.29 KiB) Viewed 2913 times


Raspuns
La prima incercare am fi tentati sa handluim in fereastra parinte mesajul WM_CTLCOLORMSGBOX, nedocumentat dar definit in WINUSER.H (alaturi de binecunoscutele WM_CTLCOLORDLG, WM_CTLCOLORSTATIC etc).

Code: Select all

#define WM_CTLCOLORMSGBOX               0x0132
Ceva simplu, de genul

Code: Select all

BOOL CALLBACK MainDialogProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch(uMsg)
   { 
   //...
   HANDLE_MSG(hWndDlg, WM_CTLCOLORMSGBOX, MainDlg_OnCtlColor);
   }
}
HBRUSH MainDlg_OnCtlColor(HWND hWnd, HDC hdc, HWND hWndChild, int type)
{
   HBRUSH hbr = NULL;
   if(CTLCOLOR_MSGBOX == type)  hbr = hCustomBrush;
   return hbr;
}
Nu merge, pentru ca WM_CTLCOLORMSGBOX nu este trimis si probabil nici nu a fost trimis vreodata de sistemul Windows.

Exista totusi o solutie.
1. Inainte de apelul lui MessageBox se creeaza un CBT (computer-based training) hook.

Code: Select all

// ...
   //  installs the hook procedure into a hook chain
   cmbv.hHook = SetWindowsHookEx(WH_CBT, CbtHookProc, g_hInstance, 
                              GetCurrentThreadId());

   // call "standard" MessageBox Windows API function 
   int nRet = MessageBox(hWnd, lpText, lpCaption, uType);
// ...
2. In procedura hook-ului se "prinde" momentul cand se creeaza message box-ul si se subclaseaza, asignandu-i o noua functie fereastra

Code: Select all

LRESULT CALLBACK CbtHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
//...
    switch(nCode)
   {
   case HCBT_CREATEWND: // a window is about to be created
      {
         LPCBT_CREATEWND lpCbtCreate = (LPCBT_CREATEWND)lParam;
         if(WC_DIALOG == lpCbtCreate->lpcs->lpszClass)
         {
            // WC_DIALOG is the class name of message box but it has not yet a window procedure
            // set. So, for the moment, keep in mind the handle to sublass it later
            // when its first child is about to be created (see below).
         }
         else
         {
            if((NULL == cmbv.lpMsgBoxProc) && (NULL != cmbv.hWnd))
            {
               // subclass the dialog 
               cmbv.lpMsgBoxProc = 
                  (WNDPROC)SetWindowLong(cmbv.hWnd, GWL_WNDPROC, 
                                         (LONG)CustomMessageBoxProc);
            }
         }
      }
      break;
// ...
   }
   return 0;
}
3. In functia fereastra putem handlui acum orice mesaj ca si pentru un dialog normal (in cazul nostru WM_CTLCOLORDLG pentru a schimba brush-ul din background).

Code: Select all

LRESULT CALLBACK CustomMessageBoxProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch(uMsg)
   {
   case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC:
      {
         HDC hDC = (HDC)wParam;
         SetBkMode(hDC, TRANSPARENT);
         return (LRESULT)cmbv.hBrush;
      }
      break;
   }
   return CallWindowProc(cmbv.lpMsgBoxProc, hWnd, uMsg, wParam, lParam);
}
Un exemplu de aplicatie completand codul de mai sus:
ColoredMessageBox.zip
(24.62 KiB) Downloaded 345 times
NOTA: Dupa acelasi principiu, in MFC putem customiza AfxMessageBox, elegant si odata pentru toata aplicatia, prin suprascrierea functiei virtuale CWinApp::DoMessageBox (vezi si Cum customizez AfxMessageBox?).


<< Back to Windows API Index



Post Reply