CWnd::GetParent causes an exception - c++

I am trying to call the function GetParent() of CWnd class.
Every time there is an exception thrown.
I'm calling the function from a working thread.
This is the line that causes the exception:
CWnd* parent = this->GetParent();
I've also tried "GetParent()->PostMessage(........);", and still the exception is thrown.
I'm using this method in a CDialog.
I have noticed that the CWnd member m_hWnd is sometimes 0x00000000 or 0x00000001.
In a different computer I don't get this exception.
Is it a problem in the project settings or in my code?

You receive an assertion and not an exception.
Here is the implementation from VS 2010:
ASSERT(::IsWindow(m_hWnd)); return CWnd::FromHandle(::GetParent(m_hWnd));
Your m_hWnd is not a window...

Related

When i use VS2022 MFC, there is an error 0x00007FFEF70E4FD3

When i use GetMenu()->GetSubMenu(2)-> 'xxx', there is an error:
Exception thrown at 0x00007FFEF70E4FD3 (mfc140d.dll) (in Menu.exe): 0xC0000005: An access violation occurred while reading location 0x0000000000008.
I added the above code at the end of the OnCreate function in the CMainFrame class.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){
GetMenu()->GetSubMenu(2)->CheckMenuItem(0, MF_BYPOSITION | MF_CHECKED);
}
3.Class "Cxxxx" does not have member "GetContextMenuManager" 'GetContextMenuManager': is not a member of'Cxxxx' After analysis, it is found that the current class Cxxx is inherited from CWinApp, which does not have the GetContextMenuManager function. If you select Use Menu Bar and Toolbar when creating a project, no error is reported. After analysis, it is found that Cxxx is derived from CWinAppEx. It has the GetContextMenuManager() member method. Therefore, do not report an error, manually modify the derived class.
It's true that GetMenu() got a null pointer. I found two solutions:
Change the value of CMFCMenuBar m_wndMenuBar in Mainfrm.h mainfrm.cpp. Delete the code of the. The compilation is successful.
When creating a project, select Use a classic menu.

MessageBox "Abnormal program termination" keeps my application running

...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 ...

How does MFC CDatabase::OpenEx function knows it is in try/catch block?

Consider next piece of code:
void CMyDB::Connect()
{
//db_ is an member object of CDatabase class
//connStr is previously defined connection string
db_.OpenEx(connStr, CDatabase::noOdbcDialog);
}
after executing Connect() -- if connection string contained wrong data, then a message box with error description will be shown.
Now if I wrap that call to Connect() in try/catch block no message box will be shown, instead an exception will be thrown:
void CMyDB::Connect()
{
try {
result = db_.OpenEx(connStr, CDatabase::noOdbcDialog);
}
catch(CDBException* e) { }
}
Now, I don't understand how OpenEx() understands that it is being wrapped by try/catch block and there is no need to show message box with error description. I know it somehow related to those MFC specific macro used inside OpenEx() (TRY, CATCH_ALL, etc.) and an AFX_EXCEPTION_LINK structure provided by them, but still can't get the whole picture.
Thanks.
It doesn't know it.
Your catch does swallow the exception, which was (before you add the try/catch) thrown to a top-level catch in your program. This top level catch was showing the Dialog Box with the error message.

MFC assertion failed when debugging

I'm not familiar with MFC but currently I must continue a project that was written in MFC. Now I'm having trouble with the following line when debugging
m_hIcon = AfxGetApp()->LoadIcon (IDR_MAINFRAME);
It always stops after the error "Assertion Failed: at afxwin1.inl". If I put a breakpoint there I saw a NULL icon handle. I tried running in release mode and it worked just fine although the handle is still NULL. I've read this question but my program is not a static library. It's a program that use a dll to connect to a CAN bus device. And the resource IDR_MAINFRAME is already in the project. It contains the default MFC icons. How can I solve this problem?
I've tried debugging and see that pModuleState changes between the first load program name call and the second load icon call. The first call returns successfully because pModuleState points to an object that has valid handle. But in the icon load call, pModuleState points to some object contains NULL handle. I also tried putting AFX_MANAGE_STATE(AfxGetStaticModuleState( )); right above the LoadIcon() call but the problem still arises
I've known the cause of this problem
UINT __cdecl RunCPRead(LPVOID pParam)
{
CMyDlg *thisclass = (CMyDlg *)pParam;
while (thisclass->m_Start)
{
thisclass->GetData();
}
return 0;
}
AfxBeginThread(&RunCPRead, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL);
After the GetData() call in RunCPRead, the control flows directly to CMyDlg's contructor although there's no object being created or copied
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMyDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
and then fails at the assignment to m_hIcon with the error "access violation while reading". I've seen the disassembly, it was the line mov dword ptr [esi+90h], eax and it's inherently a write to memory.
I don't know why. How can I solve this?
The MFC code need the correct module handle to load the resource.
Please try to read Afx*G/S*etResourceHandle.
By default MFC uses the resource handle of the main application, not of the DLL. If you are making the call in the DLL then add this line at the start of the exported DLL function:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
There is more information about this here:
http://msdn.microsoft.com/en-us/library/ba9d5yh5(v=vs.110).aspx
Assertion Errors in MFC usually happens when wrong settings are set.
go to project settings > linker > System and change subsystem to (/SUBSYSTEM:WINDOWS) this solution solved my own problem.

this pointer value changed in MFC SDI application

Now I have the following MFC SDI application code,this code comes from my view class:
void CNew_demo_appView::OnItemUpdate()
{
// TODO: Add your command handler code here
int i=this->GetListCtrl().GetSelectionMark();//get the selected item no
this->GetDocument()->unpacker.GetInformation(i,(BYTE*)(&(this->GetDocument()->fpga_info)));
UpdateFpgaAttrib updatefpgadlg;
updatefpgadlg.DisplayInfo(this->GetDocument()->fpga_info);
updatefpgadlg.DoModal();
}
void CNew_demo_appView::SetItemFpgaAttrib(int index,FPGA_INFO info)
{
this->GetDocument()->fpga_items[0]=info;
}
As you can see, I got a CDialog Derived class called UpdateFpgaAttrib, I instantialize it in the OnItemUpdate function which is called when a menu command is issued, then DoModal()
Popup the Dialog window, on that dialog, there is a button, when clicked it will call the
SetItemFpgaAttrib function which belongs to the View Class,
((CNew_demo_appView*)this->GetParent())->SetItemFpgaAttrib(0,info);
here is the problem, when this
SetItemFpgaAttrib references some data using this pointer, it always got some Access Violation Error, when I invoke this function in other View class function, it is ok,
void CNew_demo_appView::test()
{
SetItemFpgaAttrib(0,this->GetDocument()->fpga_info)
}
when triggered by the popup dialog button, it cause problem, I set break point on the SetItemFpgaAttrib , I found the this pointer value is normal 0x0041237f thing, but when triggered by the button ,it is always 0x00000001, the the GetDocument call alway cause problem. Why is the this pointer value changed,is that caused by the context or something else? I am using Vs2008 SP1
Problem solved, I just want to put the answer here for somebody else who also got this problem someday. The Problem is the
((CNew_demo_appView*)this->GetParent())->SetItemFpgaAttrib(0,info);
the GetParent() is implemented in CWnd, and it returns a CWnd*, that's the problem, the SetItemFpgaAttrib(0,info) is a function of my CDialog-Derived class CNew_demo_appView, it's not the member of CWnd, so the returned CWnd* pointer can't get the code to that function, if you do that like me, you will access some wrong place and will got Access violated error etc. I Need a function that return the original CNew_demo_appView* pointer value, the one in the m_pParentWnd is the value needed(I figure this out when I step into the CWnd::GetParent function), whilethe default GetParent did this:
return (CWnd*)ptr;
to solve this problem, I just add another function to my CDialog-Derived Class:
CWnd* UpdateFpgaAttrib::GetParentView(void)
{
return this->m_pParentWnd; //just return the parent wnd pointer
}
then call this instead of the default GetParent:
CNew_demo_appView* view=(CNew_demo_appView*)this->GetParentView();
Then everything is ok.
So conclusion: the CWnd* cast in the GetParent changed the value of the pointer.