Win api MessageBox alternative that has a set for text-align: center - c++

As I found out by searching, it is not possible to create a MessageBox() with center-aligned text.
So is there some simple alternative providing the MessageBox() functionality (including program wait for closing/accepting the box) that has an option to center-align the text?
Thanks for suggestions/examples.
PS: On Windows7+, using C++ Windows API (compiled in MS Visual Studio 2012)
EDIT:
Some useful tips:
1) Express version of Visual Studio does NOT have a resource editor/file create option:
You do have a Visual Studio "higher" than express - How to: Add a
Resource File
You have just Express version :
How to
add a resource editor for Express version
Free editor
ResEdit
This MSDN forum page contains some other useful tips like:
From the 'solution explorer', right-click the *.rc file and select
'open with..', then select 'source code (text) editor' from the list.
You might want to 'set as default' to save you repeating those
intitial steps. Once done, you should be able to manually edit the
resource script within Express.
Free XN Resource Editor
2) Visual Studio C++ how to display a dynamic message (i.e., string) in my About box?

As I found out by searching, it is not possible to create a MessageBox() with center-aligned text.
It is not possible to create a center-aligned MessageBox() dialog, as the API does not expose an option for that. But it is possible to manipulate the standard MessageBox()` dialog with some slight trickery to force it to be center-aligned.
Use SetWindowsHookEx() to create a WH_CBT hook for the thread that is calling MessageBox() (no DLL needed). The hook callback allows you to discover the HWND of the dialog that MessageBox() creates. With that, you can manipulate it however you want. In this case, you can use FindWindowEx() to get the HWND of the STATIC control for the dialog's text and then apply the SS_CENTER style to it using SetWindowLong(). For example:
LRESULT CALLBACK CenterMsgBoxTextProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_ACTIVATE)
{
HWND hDlg = (HWND) wParam;
HWND hTxt = FindWindowEx(hDlg, NULL, TEXT("STATIC"), NULL);
if (hTxt)
SetWindowLong(hTxt, GWL_STYLE, GetWindowLong(hTxt, GWL_STYLE) | SS_CENTER);
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
HHOOK hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) &CenterMsgBoxTextProc, NULL, GetCurrentThreadId());
MessageBox(...);
if (hHook) UnhookWindowsHookEx(hHook);
Alternatively, you can use SetWinEventHook() instead of SetWindowsHookEx():
void CALLBACK CenterMsgBoxTextProc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
HWND hTxt = FindWindowEx(hwnd, NULL, TEXT("STATIC"), NULL);
if (hTxt)
SetWindowLong(hTxt, GWL_STYLE, GetWindowLong(hTxt, GWL_STYLE) | SS_CENTER);
}
HWINEVENTHOOK hHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, NULL, &CenterMsgBoxTextProc, GetCurrentProcessId(), GetCurrentThreadId(), 0);
MessageBox(NULL, TEXT("test"), TEXT("test"), MB_OK);
if (hHook) UnhookWinEvent(hHook);
Here is what the result looks like in both cases:

Afaik there is not. But it is actually quite easy to create such a dialog using Win32 resources and the DialogBox function.

Related

Is there a solution for this case?

This is a Windows Desktop Application project created by Visual Studio.
I have a Dialog resource created from the Resource View that has a Static Text.
I'm using this dialog in order to show errors to the user:
DialogBox(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), hWnd, MyMessageBoxProc);
The reason I'm using a DialogBox is that I need it to stop the code execution, because the next line of code will close the application I mean the user should be aware of the error message before application exits. I know a way to change the Static Text:
HWND myMessageBox = CreateDialog(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), nullptr, MyMessageBoxProc);
HWND staticText = GetDlgItem(myMessageBox, IDC_STATIC);
SetWindowText(staticText, L"Text changed.");
But that approach doesn't stop code execution.
Since it's a Windows Desktop Application project I cannot create MFC classes and try the following approach:
// Find the Static Text.
// If called from within MyMessageBox class.
CWnd *staticText = GetDlgItem(IDC_STATIC);
staticText->SetWindowText("Text changed.");
// If called from elsewhere.
MyMessageBox myMessageBox;
CWnd *staticText = myMessageBox.GetDlgItem(IDC_STATIC);
staticText->SetWindowText("Text changed.");
So what would be a workaround in order to change the Static Text using a DialogBox without the need of MFC classes or even another approach that allows me to change the Static Text and still stop code execution like a DialogBox.
Just change the text in your window procedure (MyMessageBoxProc) by handling WM_INITDIALOG message. If you wish to supply the text to the dialog, then create it using DialogBoxParam instead, which is then accessible via the lParam parameter.
e.g.
INT_PTR MyMessageBoxProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_INITDIALOG) {
HWND hCtrl = GetDlgItem(hWnd, IDC_STATIC);
SetWindowText(hCtrl, reinterpret_cast<LPCTSTR>(lParam));
}
return FALSE;
}
The creation would be something like:
LPCTSTR text = _T("Text changed.");
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), hWnd, MyMessageBoxProc,
reinterpret_cast<LPARAM>(text));
Note that there is a standard message box that ships with windows, which you may want to use instead of writing your own. That's available via the function MessageBox

How to get HWND in ATL DLL (for SendMessage or PostMessage)

I want to get HWND in ATL DLL for SendMessage or PostMessage function in Thread.
but, ATL DLL doesn't have a window.
How to get HWND in ATL DLL?
Project Application Setting : DLL(Dynamic-link library), Security Development Lifecycle, ('not' Support MFC)
Class Option : Apartment, Aggregation Yes, Dual InterFace, Connection points.
HelloCtrl.cpp (VB Client is Handling ShowMessage())
STDMETHODIMP CHelloCtrl::ShowMessage(BSTR bstrCaption, VARIANT_BOOL* lpvbResult)
{
DWORD dwThreadID;
m_hThread_ReadData = CreateThread(NULL, 0, T_ReadData, (LPVOID)this, 0, &dwThreadID);
return S_OK;
}
DWORD WINAPI CHelloCtrl::T_ReadData(LPVOID pParam)
{
CHelloCtrl* hCtrl = (CHelloCtrl*) pParam;
::PostMessage(hCtrl->m_hWnd, WM_KEYDOWN, (WPARAM)NULL, (LPARAM)NULL);
return S_OK;
}
void CHelloCtrl::LeftButton()
{
Fire_OnMouseClick(123, 123);
}
HelloCtrl.h
#define WM_THREADFIREEVENT (WM_USER+1)
BEGIN_MSG_MAP(CHelloCtrl)
CHAIN_MSG_MAP(CComControl<CHelloCtrl>)
DEFAULT_REFLECTION_HANDLER()
MESSAGE_HANDLER(WM_THREADFIREEVENT, OnLeftButtonDown)
END_MSG_MAP()
public:
STDMETHOD(ShowMessage)(BSTR bstrCaption, VARIANT_BOOL* lpvbResult);
LRESULT OnLeftButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
void LeftButton();
private:
HANDLE m_hThread_ReadData;
static DWORD WINAPI T_ReadData(LPVOID pParam);
Window is an object that a process or module might have or might not have, or it might create one if needed. That is, your question does not have an answer without specifying what kind of window and its HWND handle you are looking for. DLL and HWND are unrelated.
From the context, it looks like you want a window which you can use for messaging and to transfer execution control between threads. That is, you post somewhere then handle elsewhere leaving the threading magic to window API.
In this case you can either reuse one of existing windows, such as window created for an ActiveX control, our you simply create your own window you fully control and use for your purposes. For the latter you derive from CWindowImpl and... see Implementing a Window with CWindowImpl. The former might be simpler might be not: ActiveX controls don't have to have a window in which case they are windowless controls. In the same time, you have an option to force windowed control using m_bWindowOnly, see How do I get the HWND for an ActiveX control after the control has been initialised/activated?.

Is it possible to create a win32 messaging window that won't be found by enumerating?

I'm trying to enumerate all win32 windows using following code:
EnumChildWindows(GetDesktopWindow(),
WindowManager::enumChildWindows,
reinterpret_cast<LPARAM>(this));
BOOL CALLBACK WindowManager::enumChildWindows(HWND hwnd, LPARAM lParam) {
WindowManager* manager = reinterpret_cast<WindowManager*>(lParam);
//
// Do stuff with child window handle (hwnd)
//
// Return TRUE to continue enumeration, FALSE to stop.
return TRUE;
}
So basically, I get the top most window by calling GetDesktopWindow( VOID ) function from WinAPI and enumerate child windows by calling EnumChildWindows( __in_opt HWND hWndParent, __in WNDENUMPROC lpEnumFunc, __in LPARAM lParam) function again from WinAPI.
Simply, my question is, can I be missing any win32 window by this approach? Could anyone hide a win32 window such that this approach can't enumerate it?
Thanks in advance.
For your way (via EnumChildWindows(GetDesktopWindow)) - it is possible: just create message-only window.
P.S. But you can enumerate message-only windows via EnumChildWindows(GetAncestor(FindWindowEx(HWND_MESSAGE,0,0,0),GA_PARENT)): see How come FindWindow finds a window that EnumChildWindows doesn't?.

C++: How to center MessageBox?

Using Visual Studio C++ with MFC. How do I center a MessageBox to it's parent window? Currently it centers to the desktop.
You need to install a hook and change the dialog box position on creation.
int MessageBoxCentered(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
// Center message box at its parent window
static HHOOK hHookCBT{};
hHookCBT = SetWindowsHookEx(WH_CBT,
[](int nCode, WPARAM wParam, LPARAM lParam) -> LRESULT
{
if (nCode == HCBT_CREATEWND)
{
if (((LPCBT_CREATEWND)lParam)->lpcs->lpszClass == (LPWSTR)(ATOM)32770) // #32770 = dialog box class
{
RECT rcParent{};
GetWindowRect(((LPCBT_CREATEWND)lParam)->lpcs->hwndParent, &rcParent);
((LPCBT_CREATEWND)lParam)->lpcs->x = rcParent.left + ((rcParent.right - rcParent.left) - ((LPCBT_CREATEWND)lParam)->lpcs->cx) / 2;
((LPCBT_CREATEWND)lParam)->lpcs->y = rcParent.top + ((rcParent.bottom - rcParent.top) - ((LPCBT_CREATEWND)lParam)->lpcs->cy) / 2;
}
}
return CallNextHookEx(hHookCBT, nCode, wParam, lParam);
},
0, GetCurrentThreadId());
int iRet{ MessageBox(hWnd, lpText, lpCaption, uType) };
UnhookWindowsHookEx(hHookCBT);
return iRet;
}
::AfxMessageBox() appears on the center of the MainFrame for me. Which is basically a call to ::MessageBox() with a handle to the MainFrame as the first parameter. Isn't that working for you?
You can't. That's why a lot of people write their own MessageBox classes.
Who said "can't"?
Try this:
This is for Win32 API, written in C. Translate it as you need...
case WM_NOTIFY:{
HWND X=FindWindow("#32770",NULL);
if(GetParent(X)==H_frame){int Px,Py,Sx,Sy; RECT R1,R2;
GetWindowRect(hwnd,&R1); GetWindowRect(X,&R2);
Sx=R2.right-R2.left,Px=R1.left+(R1.right-R1.left)/2-Sx/2;
Sy=R2.bottom-R2.top,Py=R1.top+(R1.bottom-R1.top)/2-Sy/2;
MoveWindow(X,Px,Py,Sx,Sy,1);
}
} break;
Add that to the WndProc code... You can set position as you like, in this case it just centres over the main program window. It will do this for any messagebox, or file open/save dialog, and likely some other native controls. I'm not sure, but I think you may need to include COMMCTRL or COMMDLG to use this, at least, you will if you want open/save dialogs.
I experimented with looking at the notify codes and hwndFrom of NMHDR, then decided it was just as effective, and far easier, not to. If you really want to be very specific, tell FindWindow to look for a unique caption (title) you give to the window you want it to find.
This fires before the messagebox is drawn onscreen, so if you set a global flag to indicate when action is done by your code, and look for a unique caption, you be sure that actions you take will only occur once (there will likely be multiple notifiers). I haven't explored this in detail, but I managed get CreateWindow to put an edit box on a messagebox dialog. It looked as out of place as a rat's ear grafted onto the spine of a cloned pig, but it works. Doing things this way may be far easier than having to roll your own.
Crow.
EDIT: Small correction to handle the problem raised by Raymond Chen. Make sure that parent handles agree throughout, and this should work ok. It does for me, even with two instances of the same program...

c++ create program runs in the background

i wanna make a program runs in the background and shows an icon in notification area of taskbar. I'm using win32. What api should i use? Do you know any good tutorials?
To make a program run in the background, you either add it as a service or make it "unavailable" to shutdown (for instance, hide the window for the program). To add an icon in the toolbar you use winapi. Call Shell_NotifyIcon and pass in a NOTIFYICONDATA structure
This should be defined somewhere
enum TrayIcon {
ID = 13, CALLBACKID = WM_APP+1
};
Also, in the below code the hWnd is a HWND, which is the window that you want to associate with the notification icon. This HWND's wndProc will receive the messages for the icon.
Notes:
the NIF_ICON flag makes the hIcon valid in the NOTIFICATIONICONDATA structure. So if you don't want to have an icon, don't specify it.
the NIF_MESSAGE flag makes the uCallbackMessage valid. If you don't want to handle any messages, don't specify this flag.
You have to remove the icon before you shut down your program, or it will get stuck there until you hover over it
At startup of your computer, Shell_NotifyIcon may have some difficulties to succeed. I can't find the reference for it, but I know I have read it somewhere.. So, when not successful, don't assume that it will not work at all - just try again.
With this said, this is how you add, remove and handle the messages for the tray icon
To add the icon
// in HICON hIcon: this is the icon you want as the image in the tray
NOTIFYICONDATA nid;
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = ID;
nid.uFlags = NIF_ICON | NIF_MESSAGE;
nid.hIcon = hIcon;
nid.uCallbackMessage = /*TrayIcon::*/CALLBACKID;
Shell_NotifyIcon(NIM_ADD, &nid);
To remove the icon
NOTIFYICONDATA nid;
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = /*TrayIcon::*/ID;
Shell_NotifyIcon(NIM_DELETE, &nid);
Handling the messages for the icon
LRESULT wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
// ...
case /*TrayIcon::*/CALLBACKID:
{
// here, you handle the messages for your tray icon
}
break;
// ...
}
}
http://www.winprog.org/tutorial/ is good for learning winapi and basically how Windows apps work. For the tray icon, use Shell_NotifyIcon. You will need a window, and a message loop for this.
CSystemTray works well from coeproject.
It is a wrapper around Shell_NotifyIcon.