I am trying to make it so when a messagebox opens another one opens a couple seconds later without any user input (pressing the OK button). I want the old one to stay open, but a new one to appear. I also want to be able to use SetWindowsHookEx
and set a limit on how many message boxes are created. I know this uses the function SetTimer() and needs some kind of if statement with the current number of dialogs that equal the limit and stop when the number is reached. So how do I make this work? I tried to research, but nothing seemed to work.
My attempt:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
thread_local int MsgBox_X;
thread_local int MsgBox_Y;
thread_local int Limit = 10;
static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_CREATEWND)
{
CBT_CREATEWND* s = (CBT_CREATEWND*)lParam;
if (s->lpcs->hwndParent == NULL)
{
s->lpcs->x = MsgBox_X;
s->lpcs->y = MsgBox_Y;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int MessageBoxPos(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType, int X, int Y)
{
HHOOK hHook = SetWindowsHookEx(WH_CBT, &CBTProc, NULL, GetCurrentThreadId());
MsgBox_X = X;
MsgBox_Y = Y;
int result = MessageBox(hWnd, lpText, lpCaption, uType);
if (hHook) UnhookWindowsHookEx(hHook);
return result;
if (<# of dialogs> == Limit) {
std::terminate()
}
}
void _MessageBox()
{
HWND HWND1;
MessageBox(HWND1, TEXT("Message"), TEXT("MsgBox"), MB_ICONWARNING | MB_OK);
SetTimer(HWND1,
TIMER1,
2000,
(TIMERPROC)NULL);
case WM_TIMER:
switch (wParam)
{
case TIMER1:
MessageBoxPos(NULL, TEXT("Message 2"), TEXT("MsgBox 2"), MB_ICONWARNING | MB_OK, 50, 50);
return 0;
}
}
}
int main()
{
ShowWindow(::GetConsoleWindow(), SW_HIDE);
_MessageBox();
}
You are passing an uninitialized HWND
to MessageBox()
.
Also, MessageBox()
is a blocking function, it doesn't exit until the dialog is closed, so you need to create the timer before you call MessageBox()
. Unless you use SetWindowsHookEx()
or SetWinEventHook()
to hook the creation of the dialog, then you can create the timer when the dialog's HWND
is created, and you pass that HWND
to SetTimer()
.
Also, your syntax to handle the WM_TIMER
message is just plain wrong.
That being said, MessageBox()
displays a modal dialog and runs its own message loop, so you don't need to handle WM_TIMER
manually at all. You can assign a callback to the timer, and let the modal loop dispatch the callback events for you.
Try something more like this:
#include <Windows.h>
thread_local int MsgBox_X;
thread_local int MsgBox_Y;
thread_local int NumMsgBoxes = 0;
static LRESULT CALLBACK CBTSetPosProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_CREATEWND)
{
CBT_CREATEWND* s = (CBT_CREATEWND*)lParam;
if (s->lpcs->hwndParent == NULL)
{
s->lpcs->x = MsgBox_X;
s->lpcs->y = MsgBox_Y;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int MessageBoxPos(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType, int X, int Y)
{
HHOOK hHook = SetWindowsHookEx(WH_CBT, &CBTSetPosProc, NULL, GetCurrentThreadId());
MsgBox_X = X;
MsgBox_Y = Y;
int result = MessageBox(hWnd, lpText, lpCaption, uType);
if (hHook) UnhookWindowsHookEx(hHook);
return result;
}
static void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD)
{
if (NumMsgBoxes > 0)
{
--NumMsgBoxes;
MessageBoxPos(NULL, TEXT("Message 2"), TEXT("MsgBox 2"), MB_ICONWARNING | MB_OK, 50, 50);
}
}
void _MessageBox(int NumberOfMsgBoxes)
{
NumMsgBoxes = NumberOfMsgBoxes;
if (NumMsgBoxes > 0)
{
--NumMsgBoxes;
UINT timer = SetTimer(NULL, 0, 2000, &TimerProc);
if (timer) {
MessageBox(NULL, TEXT("Message"), TEXT("MsgBox"), MB_ICONWARNING | MB_OK);
KillTimer(NULL, timer);
}
}
}
int main()
{
ShowWindow(GetConsoleWindow(), SW_HIDE);
_MessageBox(5);
}
Alternatively:
#include <Windows.h>
thread_local int MsgBox_X;
thread_local int MsgBox_Y;
thread_local int NumMsgBoxes = 0;
static LRESULT CALLBACK CBTSetPosProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_CREATEWND)
{
CBT_CREATEWND* s = (CBT_CREATEWND*)lParam;
if (s->lpcs->hwndParent == NULL)
{
s->lpcs->x = MsgBox_X;
s->lpcs->y = MsgBox_Y;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int MessageBoxPos(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType, int X, int Y)
{
HHOOK hHook = SetWindowsHookEx(WH_CBT, &CBTSetPosProc, NULL, GetCurrentThreadId());
MsgBox_X = X;
MsgBox_Y = Y;
int result = MessageBox(hWnd, lpText, lpCaption, uType);
if (hHook) UnhookWindowsHookEx(hHook);
return result;
}
static void CALLBACK TimerProc(HWND hwnd, UINT message, UINT_PTR idTimer, DWORD dwTime)
{
KillTimer(hwnd, idTimer);
if (NumMsgBoxes > 0)
MessageBoxPos(NULL, TEXT("Message 2"), TEXT("MsgBox 2"), MB_ICONWARNING | MB_OK, 50, 50);
}
static LRESULT CALLBACK CBTSetTimerProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_CREATEWND)
{
CBT_CREATEWND* s = (CBT_CREATEWND*)lParam;
if (s->lpcs->hwndParent == NULL)
{
if (--NumMsgBoxes > 0)
SetTimer((HWND)wParam, 1, 2000, &TimerProc);
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
void _MessageBox(int NumberOfMsgBoxes)
{
HHOOK hHook = SetWindowsHookEx(WH_CBT, &CBTSetTimerProc, NULL, GetCurrentThreadId());
NumMsgBoxes = NumberOfMsgBoxes;
if (NumMsgBoxes > 0)
MessageBox(NULL, TEXT("Message"), TEXT("MsgBox"), MB_ICONWARNING | MB_OK);
if (hHook) UnhookWindowsHookEx(hHook);
}
int main()
{
ShowWindow(GetConsoleWindow(), SW_HIDE);
_MessageBox(5);
}