Our application loads 3rd party DLLs that sometimes pops MessageBoxes.
We've notices that sometimes we can't just use exit(0) when there's an open MessageBox.
How can we still force an exist in such a case?
Thanks
Seems like your ugly DLL calls MessageBox (or whatever) from within DLL_THREAD_DETACH or DLL_PROCESS_DETACH.
If this happens in the same thread (i.e. the thread the calls exit) you may try to call PostQuitMessage right before the application exit. This should abort any message loop. If this happens in another thread - you may call PostThreadMessage.
There's also an option to intercept calls to Win32 API functions by hooking the appropriate module (Exe/Dll) import table. Invented by J.Richter (if I remember correctly). http://www.player.idv.tw/prog/index.php/APIHook
If you want to use brute force you may call the TerminateProcess() function. I'm not sure this is a good idea, you may want to detect if there's an open message box and send a close to it (for example using a FindWindow())
Take a look at MSDN.
Related
I want to prevent users from closing a window by Alt + F4 or by clicking the close button.
How to achieve this?
I guess the windows API can do it, but I don't have any experience, and I can't find a specific solution.
Of course, it's good to be able to implement it,don't have to use a specific API.
Background: it is very difficult to find the last place in Word after closing it for a few days. After word2013, word2013 brought with it a way to return to the previous reading position, but that thing is very unstable and often can't be saved. When word is closed, I want to stop closing and pop up a notice to remind me to add a bookmark before exiting.
EDIT: This won't work, as it turned out. At least the message hook won't work because the message is posted and not sent, and about the CBT hook I'm not sure either, and I can't test it at the moment to give an evidence-based statement. The solution is probably to subclass the window but this is also non-trivial and I can't explain it properly and with working examples right now. I can't delete this answer though because it already has a comment. See here for more info. So take it with a grain of salt. I'm turning the answer to community wiki, feel free to edit it and fix/improve the solution!
EDIT2: Seems even subclassing won't be enough because Word is doing things its own way.
You need a windows hook. Either a CBT hook or a getmessage hook will do.
You have to create a DLL for this to work. The hook handler must be located in the DLL. It must have the same bitness as Word (probably 64 Bit). Then you call SetWindowsHookEx to install a global hook.
In the hook, you will have to check whether the current action is a window-closing attempt (in a CBT hook you would check for a HCBT_SYSCOMMAND of SC_CLOSE, in a getmessage hook you would check for a WM_CLOSE message), and whether it is about a Word window (for example using the window class - not sure if it has a recognizable class, you'd have to check - or the process' executable file name which you can get using GetModuleFileName since you will run inside Word's process) and prevent the action (by returning 1 from a CBT hook or returning 0 from a getmessage hook - to allow, call CallNextHookEx).
My application is loading 3rd party DLLs, and some of this DLLs open MessageBox windows.
Is there a way for me to detect when such a window was being opened?
You'll need a CBT hook to receive a notification when a MessageBox window is displayed. You install this by calling the SetWindowsHookEx() function and specifying WH_CBT for the hook ID parameter. The hook callback function will provide you a handle to the MessageBox window, which you can then use to close it.
If you know exactly when to expect the MessageBox is being created and shown, then you can adopt a lighter and simpler approach than a global hook. This would involve calling the FindWindowEx function to get a handle to the MessageBox window, which you can likewise use to close it.
Of course, to close it properly, you will need to know which type of MessageBox it is (that is, which of the standard button choices that it displays) so that you can simulate a click of the desired button. Simply managing to get the MessageBox to disappear off of the screen without providing a valid answer is highly likely to have unexpected results in terms of the library code.
It bears explicit mention that this is really bad behavior on the part of a DLL. Unless absolutely necessary, ditch whatever 3rd party that is foisting such poorly written code upon you. If it is absolutely necessary, well then that's a red flag: work hard to eliminate it as a necessity. You shouldn't have to write and maintain gobs of code to work around their inability to get the big obvious things right.
Here's the problem: The main GUI thread is performing a SendMessage to another GUI thread (yes, there are multiple GUI threads, and unfortunately this cannot change). When that second GUI thread receives the SendMessage, it may decide to display a message box. Some of the time, that MessageBox will 'freeze' the entire application.
More specifically, the message box shows up, but the entire GUI is hung (user input does not work anywhere).
I've verified with a debugger that the second GUI thread is spinning in the DialogBox2() function defined in user32.dll. I can see in the disassembly that a message pump is being executed (I see IsDialogMessage/TranslateMessage/DispatchMessage being called). Using spy++, I do not see any messages being processed for the message dialog box window. I do see messages getting processed on the main GUI window (such as WM_SETCURSOR, though I do not thin they are being processed as I believe SendMessage doesn't execute a message pump).
The second thread is executing code that is part of an MFC extension DLL, if that matters.
I've tried using AfxMessageBox() / CWnd::MessageBox / ::MessageBox(NULL parent window,...). All exhibit the same problem.
Has anyone seen anything similar before?
Thanks,
Andrew
It must be that blocking one of the GUI threads causes the problem.
Try this:
Replace the ::SendMesage with ::PostMessage followed by a ::MsgWaitForMultipleObjects loop. You will need to pass an event handle that signals when the message box is closed.
It will probably solve the problem.
Just be careful which messages you dispatch in you ::MsgWaitForMultipleObjects loop.
According to Using Rich Edit Controls I use RichEdit in such way:
MyControl::OnCreate()
{
handle = LoadLibrary(_T("Riched20.dll"));
}
MyControl::OnDestroy()
{
FreeLibrary(handle);
}
It works fine for win32 but recently I’ve built x64 configuration and now my control fails after the page reload.
I’ve noticed that if do this:
MyControl::OnCreate()
{
handle = LoadLibrary(_T("Riched20.dll"));
FreeLibrary(handle);
handle = LoadLibrary(_T("Riched20.dll"));
}
everything works fine.
I don't wish to put this code into production, so is there any suggestions about better solution/workaround?
Since the reported fault module is Richedit20.dll_unloaded it means you are unloading the DLL while code from it is still in use.
For example, if you still have a richedit window open when you (completely) free the DLL, you can see crashes like that as soon as anything triggers a call to the control's window-proc. This is because the control's window-proc was inside the unloaded DLL code.
It should be safe to call LoadLibrary and FreeLibrary multiple times (so long as the calls balance out), so I doubt that is the problem. It may just be triggering the problem. Also, the problem was there in 32-bit builds; you just got lucky and never triggered it.
OnDestroy is the wrong place to call FreeLibrary. There are several window messages which get sent to a window after WM_DESTROY (e.g. WM_NCDESTROY).
Child windows also still exist when OnDestroy is called. If the richedits are children of your control (rather than the control itself) then moving the FreeLibrary into OnNcDestroy may save you. (Child windows are destroyed by the time WM_NCDESTROY is called.) I'd still say it's not a good place to free the library, however.
So you definitely want to move your FreeLibrary call. I would move both it and the LoadLibrary completely out of the control itself. It's not normal to have controls which load/free libraries whenever an instance of them is created. Instead, have some static init/uninit code somewhere which loads the libraries you need once and for all and frees them when the application is shutting down.
(If your app only rarely uses the control then it might make sense to load/free the library only when windows using the control are active. That situation is rare, though. Usually you're better off just leaving the DLL loaded.)
I am trying to launch an application via the ShellExecute() API call. This application contains only a main function which does some processing and exits.
Now I have put DebugBreak() in starting of main. When ShellExecute() is called the application is launched successfully but it does not ask for breaking.
How can I debug my application when launched from other application using ShellExecute()?
I am using VC++ .
If DebugBreak() isn't workign for you, try _CrtDbgBreak(). Note that _CrtDbgBreak only works in a debug build.
_CrtDebugBreak definitely works for me to make a launched process break on startup, although I'm pretty sure DebugBreak does also.
Note that both functions will make it look like the process has crashed, since they raise an exception. That is normal and gives you the opportunity to attach a debugger via the crash dialog. (The crash dialog also lets you terminate the process; don't use that, obviously.)
Also note that if you have a catch-all SEH exception handler around your main then the exception raise by DebugBreak & friends will be swallowed up and the app will simply exit without showing the crash dialog or letting you attach to it.
You can't do this with VC++; with WinDbg this is just .childdbg 1 to debug all child processes. With VC++, you can use Image File Execution Options in a pinch - check out http://codereflect.com/2009/09/20/how-to-debug-child-process-using-windbgvisual-studio/ for more info. Really though, if you've got the time to learn WinDbg, it's much better at this.
you can try this, it's ok in xp system.
app.exe is your application name,
-s1...-s3 is command line arguments.
HINSTANCE hRet = ShellExecute(NULL, L"open", L"vsjitdebugger.exe", L" app.exe -s1 a1 -s2 a2 a3 -s3", szExePath, SW_SHOW);
There is now a Microsoft Child Process Debugging Power Tool.
The method I use for things like this is to embed some interactive code, which you can either delete afterwards, comment out or conditionally enable. In a few cases we have this code enabled by querying an environment variable which is set by the tool that launches the main application. This allows me to click a check box, hit launch and have the breakpoint dialog in seconds.
if (MessageBox(NULL,
_T("Attach the debugger now, then choose Yes to hit a breakpoint"),
_T("Attach Debugger"),
MB_YESNO) == IDYES)
__debugbreak();
This gives you the ability to attach the debugger when the dialog box appears and the option to hit a breakpoint or not. My earlier versions didn't give me the option and after a while I realised some of the time I wanted the breakpoint, and some of the time I didn't.