Create a dialog in UI Thread causes crash - c++

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.

Related

Updating an CListViewCtrl from worker threads in WTL and C++

As in title I want to add/remove items to a class derived from the WTL CListViewCtrl class from worker threads, but always get "Unhandled exception thrown: read access violation."
I tried Win32 API PostMessage and SendMessage but once the worker thread touches the HWND of CListViewCtrl I get the same exception.
// CListCtrl member function, calling from worker thread
HWND GetHwnd()
{
return hwndListCtrl; // exception here
}
I tried this SafeQueue but once worker thread touches the mutex or queue then exception again.
// SafeQueue is member variable in CListViewCtrl, created in GUI thread
SafeQueue<T> m_SafeQueue;
. . .
// member function in SafeQueue class, calling from worker thread
void enqueue(T t)
{
std::lock_guard<std::mutex> lock(m); // exception here
q->push(t);
}
I tried to create the mutex and queue with new and HeapAlloc/LocalAlloc but same exception again.
I tried Win32 API CreateMutex but no luck, same exception when accessing mutex handle from worker thread.
It works fine when I add items from the GUI thread.
Only way it works from worker threads if I declare HWND or mutex and queue as static/global but I would avoid this since I want to use more than one instance from this listcontrol and I prefer any more elegant way than global variable.
I want to make this class reusable since I want to use it many times with a few modifications (more columns, different colors).
I appreciate any help and idea how I can make this work.
Environment:
VS2015 Community, WTL/C++ and Win10 Pro 64bit
I found the problem that causes access violation exception:
I declared ThreadProc callback function as static member function in CListViewCtrl class.
// DO NOT USE
// in CListViewCtrl
**static** DWORD WINAPI ThreadProc(LPVOID lp)
{
. . .
}
LRESULT OnStartWorkerThread(WORD /*wNotifyCode*/, WORD /*wID*/, HWND . ..)
{
DWORD dw;
::CreateThread(NULL, 0, this->ThreadProc, NULL, 0, &dw);
}
A working solution:
class CListViewCtrl ...
{
// thread-safe queue to store listctrl items to be added later in GUI thread
SafeQueue<CListCtrlItem<nCols> > m_SafeQueue;
// thread ID of the thread in which listctrl was created, saved in OnCreate
DWORD m_dwGuiTid;
// . . .
Check if SafeAddItem function called from GUI or any other threads
BOOL InvokeRequired()
{
if (m_GuiTid == ::GetCurrentThreadId())
return false;
return true;
}
// ...
SafeAddItem member function can be called from GUI and worker threads
void SafeAddItem(CListCtrlItem<nCols> item)
{
if (!InvokeRequired())
{
// we are in GUI thread so just add listctrl item "normal" way
AddItem(item);
return;
}
// we are in other thread so enqueue listctrl item and post a message to GUI
m_SafeQueue.Enqueue(item);
::PostMessage(m_hWnd, WM_ADD_ITEM, 0, 0);
}
// . . .
Message handler of PostMessage, we are in GUI thread
LRESULT OnAddItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
CListCtrlItem<nCols> item;
while (!m_SafeQueue.Empty())
{
item = m_SafeQueue.Dequeue();
// we are in GUI thread so we can add list ctrl items normal way
AddItem(item);
}
return 1;
}
// ...
}
And now we can add listctrl items from any threads this way. I pass this pointer to ThreadProc in _beginthreadex
m_ListCtrl.SafeAddItem(item);
The question appears to be not really about UI updates from worker thread, but about proper use of worker threads per se.
There is sufficient amount of comments about dangers of doing UI updates: they are all about potential deadlock problem. Most of the updates involve sending a message, which is a blocking API call. While you do the update from worker thread and the calling thread is blocked, any attempt from the handler in the UI to synchronize or otherwise collaboratively work with the worker may result in a deadlock. The only way around this is to prepare update in the worker thread and signal the UI thread (including by posting a message instead of sending it, in terms of SendMessage, PostMessage API) to take over and complete the updates from UI thread.
Back to original problem: you seem to be having a problem with a static thread procedure. The fourth argument in the CreateThread call is:
lpParameter [in, optional]
A pointer to a variable to be passed to the thread.
You have it NULL and you are typically to use it to pass this value to your thread procedure callback. This way you can pass execution back from static function to your class instance:
DWORD CFoo::ThreadProc()
{
// ThreadProc with proper "this" initialization
// HWND h = GetHwnd()...
}
DWORD WINAPI ThreadProc(LPVOID pvParameter)
{
return ((CFoo*) pvParameter)->ThreadProc();
}
LRESULT CFoo::OnStartWorkerThread(WORD /*wNotifyCode*/, WORD /*wID*/, HWND ...)
{
DWORD dw;
::CreateThread(NULL, 0, this->ThreadProc, (LPVOID) this, 0, &dw);
}
Also note that you are not supposed to use CreateThread directly: you have _beginthreadex and AtlCreateThread (related question).
In Windows you should never directly modify a GUI control via a worker thread. In the .NET world if we want to update a control via a worker thread we have to do a platform invoke on a Delegate which basically performs a context switch.
You have a similar problem in WIN32.
There is an excellent article on this subject I will call your attention to. It also discusses various safe workarounds:
https://www.codeproject.com/Articles/552/Using-Worker-Threads
Worker threads and the GUI II: Don't touch the GUI
"That's right. A worker thread must not touch a GUI object. This means that you should not query the state of a control, add something to a list box, set the state of a control, etc.
Why?
Because you can get into a serious deadlock situation. A classic example was posted on one of the discussion boards, and it described something that had happened to me last year. The situation is this: you start a thread, and then decide to wait for the thread to complete. Meanwhile, the thread does something apparently innocuous, such as add something to a list box, or, in the example that was posted, calls FindWindow. In both cases, the process came to a screeching halt, as all threads deadlocked."

Message loop in MFC

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));
}
}

CDockingManager GetPaneList() causes assertion failure in wincore.cpp?

So I thought this would be pretty simple, but I forgot it's MFC. Instead of registering a notification listener for data model changes that would possibly require a GUI update on each individual control I figure why not register it once and then send a message to all the open dock panes and allow them to update their controls as needed on their own terms for efficiency.
My callback function for handling the notification from the server looks something like this:
void CMainFrame::ChangeCallback(uint32_t nNewVersion, const std::vector<uint32_t>& anChangedObjectTypes)
{
CObList panes;
GetDockingManager()->GetPaneList(panes); // assert failure
if (!panes.IsEmpty())
{
POSITION pos = panes.GetHeadPosition();
while (pos)
{
CDockablePane* pPane = dynamic_cast<CDockablePane*>(panes.GetNext(pos));
if (pPane)
pPane->PostMessage(DM_REFRESH, nNewVersion);
}
}
}
The error I am getting is an assertion failure on line 926 of wincore.cpp
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL); // right here
There is a comment below this saying this can happen if you pass controls across threads however this is a single threaded MFC application and this is all being done from the main frame.
Does anyone know what else can cause this?
If there is another way to go about sending a message to all the open CDockablePane derived windows in MFC that works as well ...
Here's the obvious workaround that I didn't want to have to do but after hours of debugging and no response here I guess this is a viable answer:
I added std::vector<CDockPane*> m_dockList; to the members of CMainFrame
Now after each call to AddPane in various places that can create and open new dock panes I make a subsequent call to push_back and then I override CDockablePane::OnClose like so:
CMainFrame* pMainFrame = reinterpret_cast<CMainFrame*>(AfxGetMainWnd());
if (pMainFrame)
{
std::vector<CDockPane*>::const_iterator found(
std::find(pMainFrame->DockList()->begin(), pMainFrame->DockList()->end(), this));
if (found != pMainFrame->DockList()->end())
pMainFrame->DockList()->erase(found);
}
CDockablePane::OnClose();
Now this list will only contain pointers to open dock panes which allows me to handle the event notification in my callback and simply do a for loop and PostMessage to each.

C++ MFC server app with sockets crashes and I cannot find the fault, help!

My program has one dialog and two sockets. Both sockets are derived from CAsyncSocket, one is for listening, other is for receiving data from client. My program crashes when client tries to connect to server application and server needs to initialize receiving socket.
This is my MFC dialog class.
class CFileTransferServerDlg : public CDialog
{
...
ListeningSocket ListenSock;
ReceivingSocket* RecvSock;
void OnAccept(); // called when ListenSock gets connection attempt
...
};
This is my derived socket class for receiving data that calls parent dialogs method when event is signaled.
class ReceivingSocket : public CAsyncSocket
{
...
CFileTransferServerDlg* m_pDlg; // for accessing parent dialogs controls
virtual void OnReceive(int nErrorCode);
...
}
ReceivingSocket::ReceivingSocket()
{
}
This is dialogs function that handles incoming connection attempt when listening socket gets event notification. This is where the crash happens.
void CFileTransferServerDlg::OnAccept()
{
RecvSock = new ReceivingSocket; /* CRASH */
}
OR
void CFileTransferServerDlg::OnAccept()
{
ReceivingSocket* tmpSock = new ReceivingSocket;
tmpSock->SetParentDlg(this);
CString message;
if( ListenSock.Accept(*tmpSock) ) /* CRASH */
{
message.LoadStringW(IDS_CLIENT_CONNECTED);
m_txtStatus.SetWindowTextW(message);
RecvSock = tmpSock;
}
}
My program crashes when I try to create a socket for receiving file sent from client application. OnAccept starts when Listening socket signals incoming connection attempt, but my application then crashes. What could be wrong?
Error in debug mode:
Unhandled exception at 0x009c30e1 in FileTransferServer.exe: 0xC0000005: Access violation reading location 0xccccce58.
UPDATE:
I edited code a little and I've found that inside sockcore.cpp where Accept is defined, program failes on this line of code:
ASSERT(rConnectedSocket.m_hSocket == INVALID_SOCKET);
I don't understand how that can happen. ReceivingSocket class is somehow not getting constructed right. I derive it from CAsyncSock, leave constructor empty, and no matter where I create it, on stack or on heap, it always crashes.
Here is complete project, both client and server, if anyone can take a look at it I would be really grateful. I apologize for the comments, they are in Croatian.
Visual Studio project
I've looked into your code. The issue seems to be that you never call ListeningSocket::SetParentDlg(CFileTransferServerDlg* parent). Since you also do not initialize the m_pDlg pointer in the ListeningSocket constructor, it has random values and the program might crash here and there when you access this pointer. (I had also a crash but slightly at another location than you pointed out.)
I've changed it this way:
In ListeningSocket.h changed the constructor:
ListeningSocket(CFileTransferServerDlg* parent);
Also in ListeningSocket.cpp:
ListeningSocket::ListeningSocket(CFileTransferServerDlg* parent)
: m_pDlg(parent)
{
}
Constructor of CFileTransferServerDlg changed this way:
CFileTransferServerDlg::CFileTransferServerDlg(CWnd* pParent /*=NULL*/)
: CDialog(CFileTransferServerDlg::IDD, pParent),
ListenSock(this)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
Crash disappeared.
Other ways are possible of course.
Really nice little programs, by the way :) I'll delete them of course now since I can't probably afford the license fees :)
Maybe check to see if you've inherited ReceivingSocket correctly?
Check this out.

Assertion in VS2008 but not in VS2005

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?