...kind of. As illustrated by this extremely simplistic example,
very rarely (only once reported so far), it happens that one of my applications crashes this way. I want to terminate it as I normally do when an unspecific exception occurs. My strategy is to (low-level) log the problem, then terminate. The application is part of a subsystem and I want to (re)start it, if any problem is detected. It's built with C++-Builder 6 and runs on Windows (XP...7, also 8). I learned that an abort() most probably caused the error message. The application has a GUI, that's why a message box is shown instead of just making an (unblocking) output to stderr.
And as long as the message box isn't accepted by a user, my application keeps obviously running, for example it handles timers (the lifebeats in the above example increase) or inter-process messages, fully unaware about the problem.
After reading some answers to What is the easiest way to make a C++ program crash? and Difference between raise(SIGABRT) and abort() methods, I tried the following
void mySignalHandler(int sig)
{
// low-level error reporting here
exit(-1);
}
void __fastcall TForm1::FormCreate(TObject *Sender)
{
signal(SIGABRT, mySignalHandler);
// some more initialisation here
}
which lets my application terminate properly also if abort() or raise(SIGABRT) is called. (I also wish to prevent Windows from "searching for a solution of the problem".)
Is this (registering a signal handler for abort and calling exit there) reliable from your point of view? ...or at least something one can build upon?
In the C++Builder installation folder, check the following files:
source\cpprtl\Source\misc\errormsg.c - implementation of _ErrorMessage
source\cpprtl\Source\procses\abort.c - implementation of abort, which calls _ErrorMessage
source\cpprtl\Source\misc\assert.c - implementation of _assert, which calls _ErrorMessage
errormsg.c defines an undocumented _messagefunc function pointer that you can set to override the default behavior. Although it's undocumented and not declared in any header files, you can declare it as an extern and access it that way. Sample usage:
extern int (_RTLENTRY * _EXPDATA _messagefunc)(char *msg);
static int LogAndDie(char *msg)
{
LogMessageToSomeFile(msg);
exit(1);
return 0;
}
void InitializeErrorHandling()
{
_messagefunc = LogAndDie;
}
You might be able to use Windows Error Reporting to create a dump of the process, when an unhandled exception causes a termination. Then you can review the dump at your leisure and allow some parent-process or other watchdog to restart your process. If you chose this strategy, you would not try to deal with the failure in your code, but to allow it.
If you want to capture any program exit you should look at atexit(). If you want to capture all termination events then look at std::set_terminate(), if you want to caputure all unexpected exceptions then look at std::set_unexpected(). If you want to capture only abort() you can call signal() with the SIGABRT signal value. You can also wrap your code with try{your code}catch(...){custom event handler}.
I could do some tests, and I only can confirm that registering a SIGABRT signal handler is simply a NOOP.
I tried it with a very simple GUI application written with VS2008 Express. :
no framework, nor .NET but only Win API
one menu with Exit and Fatal
menu managed directly in WndProc
Fatal execute 1/0
Here are the result :
no special action => windows opens a MessageBox indicating a fatal error ...
signal handler for SIGABRT => same MessageBox
C++ try catch(...) => same MessageBox
SEH in WndProc : can intercept the error !
SEH around message loop : can intercept the error !
If I put bot SEH handlers, the most internal (WndProc) catches.
The good new for you is that if is enough to protect the message loop, and you do not have to go into every WndProc.
The bad new is that I do not know C++ builder and cannot say where to find the message loop.
Just to give you a clue, here is how I could protect the message loop in a WinAPI application :
__try {
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER){
::MessageBox(NULL, _T("FATAL"), _T("MAIN"), MB_OK | MB_ICONERROR);
}
That way, I can see my own message box, but nothing else and if I comment my message box the application silently exits.
But ... as the message you show is not original Windows one, I suspect C++ builder to already have such an exception handler in its message loop.
Hope it helps ...
Related
I'm trying to execute a function on user logout, but the program close before function call, is there any way to wait function finish the function execution?
#include "stdafx.h"
#include <windows.h>
#include <fstream>
using namespace std;
bool done = false;
void createFile() {
ofstream outfile("test.txt");
outfile << "test" << std::endl;
outfile.close();
}
BOOL WINAPI consoleHandler(DWORD signal) {
switch (signal)
{
case CTRL_LOGOFF_EVENT:
printf("Logoff");
done = true;
Sleep(20000); // force exit after 20 seconds
return TRUE;
case CTRL_C_EVENT:
printf("Ctrl+c");
done = true;
Sleep(20000); // force exit after 20 seconds
return TRUE;
case CTRL_CLOSE_EVENT:
printf("close");
done = true;
Sleep(20000); // force exit after 20 seconds
return TRUE;
default:
// Pass signal on to the next handler
return FALSE;
}
}
int main()
{
if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
printf("\nERROR: Could not set control handler");
return 1;
}
printf("Runing");
while (!done) {
printf(".");
Sleep(1000);
}
createFile(); //Dont called on user logout but called on close and ctrl+c
printf("\nEnding\n");
Sleep(1000);
return 0;
}
On CTRL_C_EVENT and CTRL_CLOSE_EVENT
The file test.txt is created but on
CTRL_LOGOFF_EVENT
The program close instantly, without call the function.
First, let me apologise : I'll not answer the specific 'CTRL_LOGOFF_EVENT' you are referring, but the generic feature you're trying to accomplish : 'execute a function on user logout'.
A generic way to do:
As far as I know, there is no generic way to do.
You may try various solutions :
catching events as you did
using try catch / finally
spawn windows timers and react to it
spawn threads that will wait for the main thread to end
But (as far as I know) all of them have a weakness to a way to close or another.
For instance, I recently had to struggle with a poorly coded dll I had to use. This dll was calling "exit(0)". I found no elegant way to gracefully handle this behaviour.
I had to launch it in a separated process (not thread), that I was monitoring from my main process. It's a lot of work to implement and to maintain for a simple result.
Another approach:
Depending on what you are trying to do, it may be a good practice to make your "final" operation gradually, using a format that allows you to recover partially written files.
It's what I would generally do, but it always depends on what you are trying to achieve.
For instance, if you're trying to clean your workspace, you may want to:
do it at start in the case it was not done in the previous run
work in temporary folders
Another case, if you have a very long process and want to generate summary file, you may want to:
generate a partial summary file from time to time
as you generate a new file, you move the previous one
that way, you'll have a partial summary file at every step of your process.
Since my answer has been down voted, I guess I need to be more pedantic.
first of all, since you are not getting the CTRL_LOGOFF_EVENT you may want to consult the this doc (https://learn.microsoft.com/en-us/windows/console/setconsolectrlhandler). The critical section being:
If a console application loads the gdi32.dll or user32.dll library, the
HandlerRoutine function that you specify when you call SetConsoleCtrlHandler
does not get called for the CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT events. The
operating system recognizes processes that load gdi32.dll or user32.dll as Windows
applications rather than console applications. This behavior also occurs for
console applications that do not call functions in gdi32.dll or user32.dll
directly, but do call functions such as Shell functions that do in turn call
functions in gdi32.dll or user32.dll.
To receive events when a user signs out or the device shuts down in these
circumstances, create a hidden window in your console application, and then handle
the WM_QUERYENDSESSION and WM_ENDSESSION window messages that the hidden window
receives. You can create a hidden window by calling the CreateWindowEx method with
the dwExStyle parameter set to 0.
You might also want to read ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa376890(v=vs.85).aspx ).
Now, what I had previously suggested is to use the SetWindowsHookEx which should work as all windows messages pass through it (it is what Spy uses to view the message queues (https://blogs.msdn.microsoft.com/vcblog/2007/01/16/spy-internals/)). 20 years ago, you would have to do something like this for certain messages that were not passed through to your window - as in your case where the windows message is processed up stream of the current window. You may come across old code that does this, or there may be situations that you still need to do this.
I have learned a bit about Win32 API, but now I want to learn MFC. In my ebook, they said that the CWinApp class manages main thread of application, but I can't find something like GetMessage, DispatchMessage functions in this class. So how it can begin the messages loop?
Someone explain this for me please. Sorry, I'm a newer in MFC and my English is bad.
And where can I find some ebooks/tutorials about MFC in Visual Studio?
This all done in the CWinApp:Run section.
After InitInstance returns true, CWinApp:Run is launched and the message-loop takes its role. This message-loop is tricky because it also handles OnIdle calls when the application has nothing to do.
Just look into the source code.
MFC has simplified message handling by using message-maps, programmer mostly need not to bother how message-loop is running, how messages are delivered, and how mapped-messages map to the user defined functions. I would advice you to fiddle around CWnd-derived classes (like frames, dialogs), and see how mapped-messages are calling your functions.
A WM_MOUSEMOVE is calling your OnMouseMove, provided you put an entry ON_WM_MOUSEMOVE - that's an interesting this you should find how it is working. Playing around with CWinApp-derived class isn't good idea.
MFC is somewhat like a wrapped up layer on Win32. The message loop is wrapped up inside a member of CWinThread called Run. And the application class is derived from CWinApp which is in turn derived from CWinThread. This method is not generally overridden. If the message loop code should be read, this method should be overridden and the code can be seen while debugging. It handles the idle message also
int CWinThread::Run()
{
....
for (;;)
{
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE))
{
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume "no idle" state
}
// phase2: pump messages while available
do
{
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance();
// reset "no idle" state after pumping "normal" message
//if (IsIdleMessage(&m_msgCur))
if (IsIdleMessage(&(pState->m_msgCur)))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));
}
}
I tried to create a dialog in a UI thread(CWinThread).
However, it crashes when the CDialog::Create() is called.
I had verified with previous implementation, the dialog is successfully created in non-threading mode.
Does any guru here know the crash reason of creating a dialog in CWinThread?
Without Threading:
class CProduction : public CDialog{
...
}
class CScrollProductionView : public CScrollView{
CProduction *m_pProduction;
...
}
void CScrollProductionView::OnInitialUpdate(){
m_pProduction = new CProduction(0, *m_pVisionAdapter);
m_pProduction->Create(IDD_DLG_PROD, this); //--> created dialog successfully
m_pProduction->ShowWindow(SW_SHOW);
}
Implement UI Thread:
class CProduction : public CDialog{
...
}
class CScrollProductionView : public CScrollView{
CProductionThread* m_pProdThread;
...
}
class CProductionThread : public CWinThread{
CProduction *m_pProduction;
...
}
void CScrollProductionView::OnInitialUpdate(){
m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_INIT, (LPARAM)m_pVisionAdapter);
m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_CREATE_DLG, (LPARAM)this);
}
void CProductionThread::InitMessageHandler(WPARAM wParam, LPARAM lParam)
{
printf("Receiving InitMessageHandler msg %d\n", (UINT)wParam);
switch(wParam)
{
case PROD_INIT:
{
CVisionAdapter* pAdapter = (CVisionAdapter*)lParam;
m_pProduction = new CProduction(NULL, *pAdapter);
}
break;
case PROD_CREATE_DLG:
{
CScrollProductionView* pView = (CScrollProductionView*)lParam;
m_pProduction->Create(IDD_DLG_PROD, pView); //--> Crash here
m_pProduction->ShowWindow(SW_SHOW);
}
break;
default:
break;
}
}
Error message:
Debug Assertion Failed! ..
File: .... wincore.cpp
Line: 9906
Thanks you for viewing this question.
Try not to create CWinThread, instead of creating a worker thread, if you have many communication between classes like passing object pointers, strings etc.
You will feel less headache if update the GUI through message handling.
I suspect that the problem is that your CProduction object has not been created when the PROD_CREATE_DLG message is being handled. This may be because of using PostThreadMessage. Using PostThreadMessage is fraught with problems. In particular, the messages may get lost, so the thread never sees the PROD_INIT message.
In the single-threaded code you create your CProduction object right before the Create call. Why don't you do the same in the multi-threaded code?
If you really want to use windows messages to communicate between your threads, I would create a "message only" window (See http://msdn.microsoft.com/en-us/library/ms632599.aspx#message_only) instead, as the window messages will not get lost in the same way that the thread messages do.
Alternatively, use a thread-safe queue to pass custom messages between threads, such as my example queue at http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
The crash is caused by MFC referring invalid window handle (which passed in as parent) during creation.
As a general rule, a thread can access
only MFC objects that it created. This
is because temporary and permanent
Windows handle maps are kept in thread
local storage to help maintain
protection from simultaneous access
from multiple threads.
http://msdn.microsoft.com/en-us/library/h14y172e(VS.71).aspx
an easy fix stated in the MSDN involves changing the code into
...
m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_CREATE_DLG, (LPARAM)this->GetSafeHwnd());
...
CScrollProductionView* pView = (CScrollProductionView*)CScrollProductionView::FromHandle((HWND)lParam);
m_pProduction->Create(IDD_DLG_PROD, pView);
m_pProduction->ShowWindow(SW_SHOW);
Edit:
Fixed the link to msdn.
My application (the bootstrap application for an installer that I'm working on needs to launch some other applications (my installer and third party installers for my installer's prerequisites) and wait for them to complete. In order to allow the GUI to do screen updates while waiting for an app to complete, I put a message pump in the wait loop using the 'MFC-compatible' example in the Visual Studio documentation on idle loop processing as a guideline. My code (which is in a member function of a CWinApp-derived class) is as follows:
if (::CreateProcess(lpAppName, szCmdLineBuffer, NULL, NULL, TRUE, 0, NULL, NULL,
&StartupInfo, &ProcessInfo))
{
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
if (bWait)
while (dwExitCode == STILL_ACTIVE)
{
// In order to allow updates of the GUI to happen while we're waiting for
// the application to finish, we must run a mini message pump here to
// allow messages to go through and get processed. This message pump
// performs much like MFC's main message pump found in CWinThread::Run().
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!PumpMessage())
{
// a termination message (e.g. WM_DESTROY)
// was processed, so we need to stop waiting
dwExitCode = ERROR_CANT_WAIT;
::PostQuitMessage(0);
break;
}
}
// let MFC do its idle processing
LONG nIdle = 0;
while (OnIdle(nIdle++))
;
if (dwExitCode == STILL_ACTIVE) // was a termination message processed?
{
// no; wait for .1 second to see if the application is finished
::WaitForSingleObject(ProcessInfo.hProcess, 100);
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
}
}
::CloseHandle(ProcessInfo.hProcess);
::CloseHandle(ProcessInfo.hThread);
}
else
dwExitCode = ::GetLastError();
The problem that I'm having is that, at some point, this message pump seems to free up window and menu handles on the window that I have open at the time this code is run. I did a walk through in the debugger, and at no time did it ever get into the body of the if (!PumpMessage()) statement, so I don't know what's going on here to cause the window and menu handles to go south. If I don't have the message pump, everything works fine, except that the GUI can't update itself while the wait loop is running.
Does anyone have any ideas as to how to make this work? Alternatively, I'd like to launch a worker thread to launch the second app if bWait is TRUE, but I've never done anything with threads before, so I'll need some advice on how to do it without introducing synchronization issues, etc. (Code examples would be greatly appreciated in either case.)
I've also posted this question on the Microsoft forums, and thanks to the help of one Doug Harris at Microsoft, I found out my problem with my HWND and HMENU values was, indeed due to stale CWwnd* and CMenu* pointers (obtained using GetMenu() and GetDialogItem() calls. Getting the pointers again after launching the second app solved that problem. Also, he pointed me to a web site* that showed a better way of doing my loop using MsgWaitForMultipleObjects() to control it that doesn't involve the busy work of waiting a set amount of time and polling the process for an exit code.
My loop now looks like this:
if (bWait)
{
// In order to allow updates of the GUI to happen while we're
// waiting for the application to finish, we must run a message
// pump here to allow messages to go through and get processed.
LONG nIdleCount = 0;
for (;;)
{
MSG msg;
if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
PumpMessage();
else //if (!OnIdle(nIdleCount++))
{
nIdleCount = 0;
if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
DWORD nRes = ::MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess,
FALSE, INFINITE, QS_ALLEVENTS);
if (nRes == WAIT_OBJECT_0)
break;
}
}
}
}
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
*That Web site, if you're curious, is: http://members.cox.net/doug_web/threads.htm
I think your problem is in WaitForSingleObject
Looking in MSDN you see this
Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and the CoInitialize function. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObject.
In my code in the message pump use use MsgWaitForMultipleObjects (doc).
With a call this call.
MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess, FALSE, 100, QS_ALLEVENTS);
This should stop your problem with the resources dissapearing.
When you say that window and menu handles seem to be being freed, do you mean that you've got actual HWND and HMENU values that no longer seem to work, or have you got MFC CWnd* and CMenu* variables that fail?
If the latter, the problem is most likely that you're getting the CWnd* pointers by calling CWnd::FromHandle() (or CMenu::FromHandle()) somewhere (or calling something that calls them), and OnIdle() is discarding them.
The underlying reason is that MFC maintains a map from window (or menu, etc.) handles to CWnd* objects in the system. When CWnd::FromHandle() is called, it looks for a match in the map: if one is found, it's returned. If not, a new, temporary CWnd is created, added to the map, and returned. The idea behind OnIdle() is that when it's called all message processing is done, so OnIdle() discards any of these temporary CWnd objects that still exist. That's why the CWnd::FromHandle() documentation warns that the returned pointer may be temporary.
The "correct" solution to this is to not hang onto the CWnd* pointers returned from CWnd::FromHandle(). Given the simplicity of your application, it might be easier to just remove the call OnIdle(): this shouldn't have any negative effects on an installer.
Of course, this is all something of a guess, but it sounds plausible...
There is a Windows function called DisableProcessWindowsGhosting (see http://msdn.microsoft.com/en-us/library/ms648415(v=vs.85).aspx) that prevents Windows from 'ghosting' your window, and continue updating the window (your animation).
After switching from VS2005 to VS2008 SP1, I found an issue that I can't explain.
A program works fine under VS2005 in both release and debug mode. Under VS2008, when entering the debugger an assert is raised.
If I let the program run (in debug or release mode), no assertion at all.
I spent almost two days on this and I don't understand what I do wrong.
Description of the program:
I have a MFC dialog based program that creates a user thread (CWinThread) that creates the main dialog of the application.
A worker thread loops infinitely and posts each second a message to the dialog. The message is processed in the gui thread.
Some parts of my code:
The InitInstance of the gui thread:
BOOL CGraphicalThread::InitInstance()
{
CGUIThreadDlg* pDlg = new CGUIThreadDlg();
pDlg->Create(CGUIThreadDlg::IDD);
m_pMainWnd = pDlg;
AfxGetApp()->m_pMainWnd = pDlg;
return TRUE;
}
The worker thread:
UINT ThreadProc(LPVOID pVoid)
{
do
{
AfxGetApp()->m_pMainWnd->PostMessage(WM_APP+1, (WPARAM)new CString("Hello"), NULL);
Sleep(1000);
}
while(!bStopThread);
return 0;
}
The dialog message handler is like this:
LRESULT CGUIThreadDlg::OnMsg(WPARAM wp, LPARAM lp)
{
CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST1);
CString* ps = (CString*)wp;
pList->InsertString(-1, *ps);
delete ps;
return 1L;
}
This works perfectly fine with VS2005.
But with VS2008, but as soon as a put a breakpoint and enter the debugging mode, I have an assertion raised ???
wincore.cpp line 906
CObject* p=NULL;
if(pMap)
{
ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
}
ASSERT((CWnd*)p == this); // must be us
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
If I remove the GUI thread and create the dialog into the CWinApp thread, the problem doesn't occur anymore.
Does anybody have any idea?
Am I doing something wrong?
Thank you
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
#Ismael: I had already tried that the assert is still fired. The only way I found to remove the assert is to create the dialog into the CWinApp thread.
But this doesn't explain what happens since there's still the worker thread that post to the dialog every second.
Anyway , thanks.
#daanish.rumani: I've checked the wincore.cpp and the CWnd::AssertValid() is exactly the same (but there's of lot of differences in the rest of the files).
I would accept that a piece of code works with VS2005 and not VS2008, but
I can't see what I do wrong.
If I do something wrong, what is the correct way to proceed?
Why the assert is only fired when a breakpoint is hit and I step over the Sleep call?
I can run the program fine, even when its compiled in debug mode, as long as I don't enter the debugger.
Could it be a bug in the debugger?