Set location of MessageBox? - c++

I want to print out a message using MessageBox (or similar). I would also like control over where exactly on the screen the box appears but can find nothing in the description of MessageBox that allows you control over the location. Did I miss something? If MessageBox can not be used, then is there an alternative?
For reasons too complex to go into here, I would prefer an answer which didn't involve making my own window and passing the address of a callback function.

Step 1: Create a CBT hook to trap the creation of the message box:
// global hook procedure
HHOOK hhookCBTProc = 0;
LRESULT CALLBACK pfnCBTMsgBoxHook(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_CREATEWND)
{
CREATESTRUCT *pcs = ((CBT_CREATEWND *)lParam)->lpcs;
if (pcs->style & WS_DLGFRAME || pcs->style & WS_POPUP)
{
HWND hwnd = (HWND)wParam;
// At this point you have the hwnd of the newly created
// message box that so you can position it at will
SetWindowPos(hwnd, ...);
}
}
return CallNextHookEx(hhookCBTProc, nCode, wParam, lParam);
}
Step 2: Install/remove the hook before and after showing the message box:
// set hook to center the message box that follows
hhookCBTProc = SetWindowsHookEx(WH_CBT,
pfnCBTMsgBoxHook,
0, GetCurrentThreadId());
int sResult = MessageBox(hwndParent, pszMsg, pszTitle, usStyle);
// remove the hook
UnhookWindowsHookEx(hhookCBTProc);

If I needed additional behavior for a Messagebox I always created my own window and made it look like a standard MessageBox. You do it right once and you can always reuse it in other projects.

MessageBox is a basically a set of defaults. Don't like them? Bring your own. If you don't want a real window with all its complexities, but MessageBox is too restrictring, create a dialog.

You could do this with a CBT hook procedure. There is an MSDN article on how to do this in VB but converting it to C++ wouldn't be hard.
http://support.microsoft.com/kb/180936

Related

Win32: C++: How do I re-focus on Parent Window after clicking in a child window?

In my Win32 CPP program, I have defined some Child Window to display various text strings using something like:
hnd_to_this_ch_window = CreateWindow(
L"EDIT",L"Some initial text", WS_VISIBLE | WS_CHILD | ES_LEFT,
position_of_this_window_X,
position_of_this_window_Y,
TEXTOUT_DEFAULT_WIDTH,
TEXTOUT_DEFAULT_HEIGHT,
handle_to_my_parent_window, NULL,
hinstance_variable_used_by_create_window,
NULL )
My problem is that if I click with my mouse to select the text in one of such child windows (to, say, copy it somewhere), the focus of the application goes to this child window and so any keypresses which used to be handled through my main windows CALLBACK (with case WM_KEYDOWN:) are now captured into the child window, where they appear as inputted characters. What magic function do I call to have the focus go back to the parent (so that my WM_KEYDOWN) can work again? I was hoping I could just click on the main Window's title bar and that would take it back to normal, but that isn't working (because, obviously, my program is lacking some extra logic).
Handle the WM_KILLFOCUS message in the window procedure of the window you want to focus, and restore the focus using the SetFocus function.
If you want to focus the window when it is clicked, handle the WM_LBUTTONDOWN message.
LRESULT CALLBACK MyWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
// Restore the focus when it was lost.
if (Msg == WM_KILLFOCUS) {
SetFocus(hWnd);
// Msg was handled, return zero.
return 0;
}
// Or when the window is clicked.
if (Msg == WM_LBUTTONDOWN) {
SetFocus(hWnd);
// Msg was handled, return zero.
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
case WM_KEYDOWN:
SetFocus(Parent_Hwnd);
return SendMessage(Parent_Hwnd,WM_KEYDOWN,wParam,lParam);

Low Level keyboard hook never catches WM_KEYDOWN

I'm trying to create macro application that will start running certain operations when key is pressed (system wide shortcut). I did created Windows Form Application with Visual Studio 2012. When form is loaded keyboard hook is installed:
HookHandle = SetWindowsHookEx( WH_KEYBOARD_LL, (HOOKPROC)keyboardHookHandler, GetModuleHandle(NULL), NULL);
if( HookHandle == 0){
MessageBox::Show("Error setting hook!");
}
My hook callback function is:
public: static LRESULT CALLBACK keyboardHookHandler( int code, WPARAM wParam, LPARAM lParam ) {
if(code>=0 && wParam == WM_KEYDOWN){
MessageBox::Show("Key Down");
}
return CallNextHookEx( HookHandle, code, wParam, lParam);
}
When I do compile application and run it message box is never shown. More to say I know this call back function is fired but wParam always contains value 45 (I did checked and none of those WM constants that should be returned has value 45). Also after few key events application crashes.
What is the reason why this code doesn't work like it should to?
Update:
I did removed cast to HOOKPROC and changed it to delegated procedure:
private:
delegate LRESULT CALLBACK HOOKPROC( int code, WPARAM wParam, LPARAM lParam );
HOOKPROC^ keyboardHookProcedure;
And hook setting to:
keyboardHookProcedure = gcnew HOOKPROC(this, &MyForm::keyboardHookHandler);
HookHandle = SetWindowsHookEx( WH_KEYBOARD_LL, keyboardHookProcedure, GetModuleHandle(NULL), NULL);
But now I have this problem:
error C2664: 'SetWindowsHookExW' : cannot convert parameter 2 from 'WindowsFormTest::MyForm::HOOKPROC ^' to 'HOOKPROC'
If you're trying to catch a unique key combination globally, it might be simpler to use RegisterHotKey. It defines a system-wide hot key with no need for hooks or anything special. It is going to override the foreground process handling, so this won't be ideal if you're trying to register a common key combo.

C++ Modeless Dialog created from DLL doesn't process input properly

I am having issues with creating a modeless dialog from a DLL file. My dialog has nothing special on it, just an OK button and an edit box. I have looked at this Microsoft KB Article (http://support.microsoft.com/kb/233263) and have implemented its solution to create a window hook to grab and process messages.
The method provided by Microsoft solves the tab key problem, however, it creates another problem. When I type into the edit box on the dialog, whatever I press is duplicated 4 times. For example, if I press 'a' on the keyboard, 'aaaa' will show up in the edit box.
If I disable the Window Hook, then the edit box works correctly and only displays one 'a'.
What do I need to do to the Window Hook procedure to solve this problem?
Any help is greatly appreciated.
- - EDIT - -
As per request, my Window Hook Procedure Code: (It's the same as the KB article)
LRESULT FAR PASCAL GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) {
LPMSG lpMsg = (LPMSG) lParam;
if (nCode >= 0 && PM_REMOVE == wParam) {
// Don't translate non-input events.
if ((lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST)) {
if (IsDialogMessage(hwndDllDlg, lpMsg)) {
// The value returned from this hookproc is ignored,
// and it cannot be used to tell Windows the message has been handled.
// To avoid further processing, convert the message to WM_NULL
// before returning.
lpMsg->message = WM_NULL;
lpMsg->lParam = 0;
lpMsg->wParam = 0;
}
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
My Dialog Callback Procedure:
BOOL CALLBACK DllDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG:
hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, NULL, GetCurrentThreadId());
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
DestroyWindow(hwndDlg);
hwndDllDlg = NULL;
}
return TRUE;
case WM_DESTROY:
UnhookWindowsHookEx(hHook);
return FALSE;
}
return FALSE;
}
}
Both hHook and hwndDllDlg are defined as HHOOK and HWND respectively.
HHOOK hHook;
HWND hwndDllDlg = CreateDialog(0, MAKEINTRESOURCE(DLG_MAIN), 0, DllDlgProc);
I looked at the KB article. It sounds reasonable. There is some point where you was not enough accurate while following the instructions from KB. Post your code. This may help.
If you have control over the message pump of the executable and can add IsDialogMessage there, then you do not need any hook. Code from the dll is part of the code of the process. Window handles are in the common space either.
Other approach is starting your own UI thread. If you create your dialog on this thread, then you will have your own message pump. The hook will not be needed in this case either.
Well, this is more of a question to author of the post..
I have the tab key issue and am trying to understand the microsoft article better.
So my dialog is shipped out as Dll and the application which I don't have access to is launching dialog from my dll.
HWND hwndDllDlg = CreateDialog(0, MAKEINTRESOURCE(DLG_MAIN), 0, DllDlgProc);
I don't understand what dialog the code refers to when they said hwndDllDlg in the article. Should I point my dialog creation to this variable ?

WM_PASTE hook not working

I want to detect everytime I paste something. It's just something to make some data entry work simpler.
I set a global hook and then "wait" for the wm_paste. This is part of the code I have:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0)//Do not process the message
return CallNextHookEx(msg_hook,nCode,wParam,lParam);
LPMSG m=(LPMSG)lParam;
if(m->message == WM_PASTE)
{
OutputString("Paste detected!\n");
}
if(m->message == WM_PASTE)
{
OutputString("Paste detected!\n");
}
return CallNextHookEx(msg_hook,nCode,wParam,lParam);
}
//DLL_ATTACH:
...
if(strstr(ProcName, LOADERNAME))
{
InitCommonControls();
if(!(msg_hook=SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hinstDLL, 0)))
{
ErrorExit(TEXT("SetWindowsHookEx"));
//MessageBox(0, "WH_GETMESSAGE", 0, 0);
//return -1;
}
}
WM_PASTE debug string never gets printed. I'm aware that not all applications use WM_PASTE. But at least notepad should work.
Any suggestions?
Thanks!
In GetMsgProc, the wParam parameter is not the message being intercepted, but a flag that indicates whether or not the message in lParam and been removed from the message queue.
You should be using m->wParam instead.
Wm_paste message is fired only in combo box and edit control. There is no easy way to capture paste, but you can get copy message by creating a tiny window and adding this window to the chain of clipboard viewers.

Safely remove window subclassing?

I am trying to subclass the currently focused window on a Windows system using a global CBT hook. This is related to what happens in this question, but the bug is different.
What happens when this subclassing is in effect, is that Opera's (version 10.50) main window is prevented from displaying. Opera has a "splash screen" where you are required to click "Start" for the main window to show that appears after Opera has not shut down properly. Whenever this window pops up, Opera's main window won't show. If Opera was shut down properly, and this splash screen does not show, the main window displays as it should.
HHOOK hHook;
HWND hWndSubclass = 0;
void SubclassWindow(HWND hWnd)
{
Unsubclass();
FARPROC lpfnOldWndProc = (FARPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LPARAM)SubClassFunc);
SetProp(hWnd, L"PROP_OLDWNDPROC", lpfnOldWndProc);
hWndSubclass = hWnd;
}
void Unsubclass()
{
if (hWndSubclass != 0 && IsWindow(hWndSubclass))
{
FARPROC lpfnOldWndProc = (FARPROC)GetProp(hWndSubclass, L"PROP_OLDWNDPROC");
RemoveProp(hWndSubclass, L"PROP_OLDWNDPROC");
SetWindowLongPtr(hWndSubclass, GWLP_WNDPROC, (LPARAM)lpfnOldWndProc);
hWndSubclass = 0;
}
}
static LRESULT CALLBACK SubClassFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_MOVING)
{
// do something irrelevant
}
else if (message == WM_DESTROY)
{
Unsubclass();
}
FARPROC lpfnOldWndProc = (FARPROC)GetProp(hWndSubclass, L"PROP_OLDWNDPROC");
return CallWindowProc((WNDPROC)lpfnOldWndProc, hWndSubclass, message, wParam, lParam);
}
static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_SETFOCUS && hWndServer != NULL)
{
SubclassWindow((HWND)wParam);
}
if (nCode < 0)
{
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
return 0;
}
BOOL APIENTRY DllMain( HINSTANCE hInstance,
DWORD Reason,
LPVOID Reserved
)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
hInst = hInstance;
return TRUE;
case DLL_PROCESS_DETACH:
Unsubclass();
return TRUE;
}
return TRUE;
}
My suspicion is that Opera's main window is somehow already subclassed. I imagine the following is happening:
The window is created with it's own basic WndProc, and is given focus
My application subclasses the window, storing the original WndProc
Opera subclasses its own window
When the window loses focus, I restore the original WndProc, thus ignoring the second WndProc
Can this really be the case? Are there any other explanations?
This can happen, as Raymond Chen writes:
Consider what would happen if somebody else had subclassed the window during the "... do stuff ..." section. When we unsubclassed the window, we would have removed two subclasses, the one we installed, and the one that was installed after us. If the other subclass allocated memory (which is very common), then that memory got leaked, in addition to the subclass failing to do whatever it was trying to do.
He continues with a solution:
This is quite a cumbersome process, so the shell team wrote some helper functions to do all this for you. The SetWindowSubclass function does all the grunt work of installing a subclass procedure, remembering the previous one, and passing reference data to the subclass procedure you provide. You use the DefSubclassProc function to forward the message to the previous subclass procedure, and when you're done, you use the RemoveWindowSubclass function to remove yourself from the chain. RemoveWindowSubclass does all the work to do the right thing if you are not the window procerure at the top of the chain.