MFC Debug Assertation Failed!! wincore.cpp Line 972 - c++

I have created an MFC Dialog box in a DLL for use in multiple projects and it has functionalities such as:
Getting Listbox data from the main application using the DLL. I can push string data through the main application to the MFC Dialog box but I am getting Assertation errors after compilation.
This process happens in a thread where one thread keeps the Dialog box active and another pushes data as shown in the code below.
void dbox(CDialogClass *dlg)
{
dlg->ShowDlg();
}
void input(CDialogClass *dlg)
{
string str1= "";
while (1)
{
getline(cin, str1);
//cin >> str1;
dlg->SetData(str1);
}
}
int main()
{
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
}
else
{
CDialogClass *dlg = new CDialogClass("Title Dbox",300.0f, 300.0f, 0);
thread t1(input, dlg);
thread t2(dbox, dlg);
t1.join();
t2.join();
}
}
return 0;
}
Here dbox() invokes a ShowDlg function which is in an MFC DLL as below:
void CDialogClass::ShowDlg()
{
dlgg->title = title;
dlgg->dialogWidth = D_width;
dlgg->dialogHeight = D_height;
dlgg->pos = pos;
dlgg->Create(IDD_DIALOG1);
dlgg->ShowWindow(SW_SHOWNORMAL);
dlgg->RunModalLoop();
//dlgg->DoModal();
}
SetData() is called by thread input() and it has the below code in the DLL:
void CDialogClass::SetData(string data)
{
p_text = data;
dlgg->calldata(data);
}
Below is the code for my Dialog class in the DLL just for reference if needed-
#include "stdafx.h"
#include "DlgDisp.h"
#include "afxdialogex.h"
#include "Resource.h"
#include <fstream>
#include <Thread>
IMPLEMENT_DYNAMIC(CDlgDisp, CDialogEx)
CDlgDisp::CDlgDisp(CWnd* pParent /*=NULL*/)
: CDialogEx(CDlgDisp::IDD, pParent)
{
}
CDlgDisp::~CDlgDisp()
{
}
void CDlgDisp::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST1, m_listbox);
}
BOOL CDlgDisp::OnInitDialog()
{
//Title manipulations
char *str_title;
str_title = &title[0];
SetWindowText((CAtlString)str_title);
//Size manipulations
CWnd* pctrl = GetDlgItem(IDC_LIST1);
CRect rectctrl;
SetWindowPos(NULL, 0, 0, dialogWidth, dialogHeight, SWP_NOMOVE | SWP_NOZORDER);
pctrl->GetWindowRect(rectctrl);
pctrl->SetWindowPos(NULL, 20, 20, dialogWidth-120, dialogHeight-80, SWP_NOMOVE | SWP_NOZORDER);
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
BEGIN_MESSAGE_MAP(CDlgDisp, CDialogEx)
END_MESSAGE_MAP()
void CDlgDisp::calldata(string strdata)
{
char *str_parameter;
str_parameter = &strdata[0];
CString param = _T("");
param.Format(_T("%s"), (CAtlString)str_parameter);
if (pos == 0)
{
m_listbox.InsertString(0, param);
}
else
m_listbox.AddString(param);
UpdateData(FALSE);
}
the flow of the program for references:
CDlgDisp class is the Dialog class derived from CDialogEx class.
CDialogClass is for interaction with external applications which is derived from CDialog class.
CDialogClass has a public member variable of CDlgDisp class.
external application -> object.CdialogClass -> object.CDlgdisp class
when I execute the program it runs well, and I get an error when I try to input data through the console. It does get printed in the Listbox dynamically but then it shows the Assertation Error.
Here is an image after execution
[enter image description here][1]
and here is the image after I enter the data in console and press enter
[enter image description here][2]
what do you guys think the problem is?
[1]: https://i.stack.imgur.com/pXFMD.png
[2]: https://i.stack.imgur.com/eUXZ7.png

Look into the source where the ASSERT ion take place
You find this comment:
// 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.
MFC window objects use handle maps per thread. This usually doesn't allow you to use the objects for some functions from other threads. It is possible but this is discussed in many other threads.
The way you want to use the MFC isn't possible. Think about synchronisation. If the functions are thread safe that you want to use with the other window you may use SendMessage and the m_hWnd handle directly.

Thank you guys for being first responders to my problem. All the comments were useful and helped me in understanding the problem.
Problem: Since MFC is thread-safe therefore using an object to SetData was creating a memory sharing conflict between both the threads.
Solution: I used a custom message to pass information to be displayed dynamically. Below Links helped completely-
https://blog.csdn.net/xust999/article/details/6267216
On sending end:
::PostMessage(HWND_BROADCAST, WM_UPDATE_DATA, 0, 0);
On receiving end in the header file:
const UINT WM_UPDATE_DATA = ::RegisterWindowMessage(_T("UpdateData"));
Also, in the header file in the Dialog class:
afx_msg LRESULT OnUpdateData(WPARAM wParam, LPARAM lParam);
The above function will be called when the message is posted and all functionalities to be added to it such as-
LRESULT CDlgDisp::OnUpdateData(WPARAM wParam, LPARAM lParam)
{
char *str_parameter;
str_parameter = &parameter[0];
CString param = _T("");
param.Format(_T("%s"), (CAtlString)str_parameter);
if (pos == 0)
{
m_listbox.InsertString(0, param);
}
else
m_listbox.AddString(param);
return 1;
}
Thank you, Everyone.

Related

Open a MFC dialog in a std::thread

I would like to show a dialog to inform the user that the application is busy. To avoid blocking of the main thread, I was thinking to use a std::thread to show the dialog. Consider the following code:
InProcDlg inProcess;
std::thread t([ &inProcess ] {
inProcess.DoModal();
delete inProcess;
});
// wait till process has finished
::PostMessage(inProcess.m_hWnd, WM_USER + 1, 0, 0);
if (t.joinable()){
t.join();
}
InProcDlg.cpp
BEGIN_MESSAGE_MAP(InProcDlg, CDialogEx)
...
ON_MESSAGE(WM_USER + 1, &InProcDlg::close)
END_MESSAGE_MAP()
LRESULT InProcDlg::close(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam, lParam);
EndDialog(1);
return 0;
}
Running this code the dialog is shown properly. The dialog is also closed, but the main dialog is not shown, the application hangs in CreateRunDlgIndirect(). Trying to step in, while setting some breakpoints the main dialog is shown properly back again. Very strange. I would be very happy for any advices where I have to dive deeper in.
In the next step I would also like to show the process to the user, by sending an integer indicating the current state of process.
int *percent;
::PostMessage(inProcess.m_hWnd, WM_USER + 2, 0, reinterpret_cast<LPARAM>(percent));
How I can gain evidence that the dialog is already existing, before sending or posting a message?
I'm using Visual Studio 2013.
I can think of two ways to do that:
Modeless dialog
https://www.codeproject.com/Articles/1651/Tutorial-Modeless-Dialogs-with-MFC
User thread (UI thread)
Creating a brother to the main UI thread (CWinApp) by using CWinThread. Most important is to assign CWinThread::m_pMainWnd member, with a pointer to a Dialog. If the dialog is Modal you return FALSE right after the call to DoModal, and return TRUE for Modeless.
class CMainFrame : public CFrameWnd {
// pointer to thread
CWinThread* m_pUserThread;
}
start thread
m_pUserThread = AfxBeginThread(RUNTIME_CLASS(CUserThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED );
m_pUserThread->m_bAutoDelete = TRUE;
m_pUserThread->ResumeThread();
headr file**
class CUserThread : public CWinThread
{
DECLARE_DYNCREATE(CUserThread)
public:
CUserThread();
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CUserThread)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
//}}AFX_VIRTUAL
protected:
virtual ~CUserThread();
// Generated message map functions
//{{AFX_MSG(CUserThread)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
CUserMsg* m_pDlg;
}
source file
#define DO_MODAL
BOOL CUserThread::InitInstance()
{
#ifdef DO_MODAL
// create and assign Modeless dialog
CUserMsg dlg;
m_pMainWnd = &m_pDlg;
dlg.DoModal();
return FALSE;
#endif
#ifdnef DO_MODAL
// create and assign Modal dialog
m_pDlg = new CUserMsg();
m_pDlg->Create( IDD_USER_DLG, AfxGetMainWnd() );
m_pMainWnd = m_pDlg;
return TRUE;
#endif
}
int CUserThread::ExitInstance()
{
// check for null
m_pDlg->SendMessage( WM_CLOSE ) ;
delete m_pDlg;
return CWinThread::ExitInstance();
}
to terminate the thread
// post quit message to thread
m_pUserThread->PostThreadMessage(WM_QUIT,0,0);
// wait until thread termineates
::WaitForSingleObject(m_pUserThread->m_hThread,INFINITE);
For both ways I would highly recommend making the dialog as a top most window:
BOOL CLicenseGenDlg::OnInitDialog() {
CDialog::OnInitDialog();
// TODO: Add extra initialization here
SetWindowPos( &wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | WS_EX_TOPMOST );
return TRUE;
}

MFC - UpdateData(False) + Thread + Debug assertion failed

Im using Visual Studio 2010, work with MFC 2008/2010.
I have a problem with THREAD and UPDATEDATA(FALSE)
This is init function
BOOL CBkav_btap2_appDlg::OnInitDialog(){
....
AfxBeginThread (MyThreadProc,(LPVOID)GetSafeHwnd());
return TRUE; // return TRUE unless you set the focus to a control
}
This is my THREAD
UINT __cdecl MyThreadProc( LPVOID pParam )
{
DWORD totalphys;
DWORD availablephys;
DWORD memoload;
CBT2Class* pObject = (CBT2Class*)pParam;
pObject->GetRAMandCPUInfo(totalphys,availablephys,memoload );
CBkav_btap2_appDlg dlgObject;
dlgObject.ec_totalphys = totalphys;
dlgObject.UpdateData(FALSE);<--- Can not update data
return 0;
}
CBT2Class is the class in dll file i created before.
ec_totalphys is just an edit_control.
When i run, it return "Debud Assertion failed". I dont know why. Please help me. Thankss.
p/s: I think i need use SendMessage to update data for Dialog but i search every where but still can't work.
You are passing an HWND as the thread parameter. It is not a pointer and you should not cast it to anything. You can use the HWND to post a custom message to the dialog. This custom message can include data in wParam and lParam. The message handler in the dialog runs in the main thread and can do the UpdateData call. See the example here for posting a custom message to the dialog: http://vcfaq.mvps.org/mfc/12.htm
OK. Thanks all for suggestions :D.
So my particular solution is :
B1. Defined a MESSAGE
#ifdef _DEBUG
#define new DEBUG_NEW
#define WM_MY_MESSAGE (WM_USER+1000) // Cho chay o 2 thoi diem khac nhau
#endif
B2. Signed in a MESSAGE MAP
BEGIN_MESSAGE_MAP(CBkav_btap2_appDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(WM_MY_MESSAGE, TestMessageCall)
ON_WM_TIMER()
END_MESSAGE_MAP()
B33. Create Thread
BOOL CBkav_btap2_appDlg::OnInitDialog()
{
..
// TODO: Add extra initialization here
AfxBeginThread(TestMethodThreadCall, (LPVOID)GetSafeHwnd());
return TRUE; // return TRUE unless you set the focus to a control
}
B4. Create Method
UINT __cdecl TestMethodThreadCall( LPVOID pParam )
{
while(1){
//Ten Chuong trinh dc su dung nhieu nhat
HWND hDlg = (HWND )pParam;
CString nameTestMessage = __T("Call From Message");
::SendMessage(hDlg, WM_MY_MESSAGE, (WPARAM)(&nameTestMessage), 0);
Sleep(5000);
}
return 0;
}
B5. Create Method Message call
LRESULT CBkav_btap2_appDlg::TestMessageCall(WPARAM wpD, LPARAM lpD)
{
CString *pwpD = (CString *)wpD;
ec_nameTestmessage = *pwpD;
UpdateData(FALSE);
return LRESULT();
}

Worker threads and MFC controls

I'm aware of the fact that MFC GUI controls are not accessible directly from a worker thread, but for example, they getting by passing to this thread a pointer to the object instance that owns the controls. My problem is, that I'm really sure about how it goes when I'm calling functions within the scope of the worker thread, which needs to access MFC controls. Please consider the following code:
//header:
class CMyDlg : public CDialog
{
...
...
...
afx_msg void OnButtonControl();
static UNIT ControlThread(LPVOID pParam);
bool ValidateEditControl();
}
//cpp
void CMyDlg::OnButtonControl()
{
CString Text = "Hello";
GetDlgItem(IDC_EDIT_HELLO)->SetWindowText(Text);
m_hControlThread = AxtBeginThread(ControlThread, this);
}
UINT CMyDlg::ControlThread(LPVOID pParam)
{
CMyDlg *dlg = (CMyDlg*) pParam;
CString Text = "Hello";
while(SomethingIsTrue) {
bool Ret = dlg->ValidateEditControl();
if (!Ret) //Someone changed ControlEntry -> change it back
dlg->GetDlgItem(IDC_EDIT_HELLO)->SetWindowText(Text);
}
AfxEndThread(0);
}
bool CMyDlg::ValidateEditControl()
{
CString Text;
this->GetDlgItem(IDC_EDIT_HELLO)->GetWindowText(Text); // do I need the "this" pointer here, or for general how do I access my MFC control at this point?
if (Text == "Hello")
return true;
else
return false;
}
What is the best way to this?
Thank you in advance
best Greg
Without going into too much details, here is how you should do it. I have't build, judged or modified your basic code, I have just addressed your threading part of question. You should be able to take it from here.
UINT CMyDlg::ControlThread(LPVOID pParam)
{
HWND hWnd = (HWND) pParam;
CString Text = "Hello";
while(SomethingIsTrue) {
bool Ret = SendMessage(HwND, VALIDATE_CONTROL,0,0 );
if (!Ret) //Someone changed ControlEntry -> change it back
SendMessage(CHANGE_EDIT_HELLO, &Text, 0);
}
AfxEndThread(0);
}

OnPaint is updated too often

I have a problem with the OnPaint method of CFrameWnd, and I cant seem to figure out what is happening. OnPaint is called approx every 10 ms, which causes the computer to freeze. Checked CPU usage and this app takes up 50%!
The application is a very simple MFC app, which is written in one file.
// Includes are done here...
class MFC_Tutorial_Window : public CFrameWnd
{
std::string data;
public:
MFC_Tutorial_Window()
{
this->data = "";
Create(NULL, "Data Win"); // Create window
}
void OnPaint()
{
CDC* pDC = GetDC();
CString s = CString(this->data.c_str());
RECT rc;
HWND hwnd = this->m_hWnd;
if(hwnd != NULL) {
::GetWindowRect(hwnd, &rc);
rc.top = rc.bottom/2;
if(pDC != NULL && pDC->m_hDC != NULL) {
pDC->DrawText(s, &rc, DT_CENTER);
}
}
}
void UpdateWithNewData(std::string up) {
this->data = up;
Invalidate();
}
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(MFC_Tutorial_Window, CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()
// App class
class MyApp :public CWinApp
{
MFC_Tutorial_Window *wnd;
BOOL InitInstance()
{
wnd = new MFC_Tutorial_Window();
m_pMainWnd = wnd;
m_pMainWnd->ShowWindow(3);
wnd->UpdateWithNewData("Hello world!");
return 1;
}
};
Does anyone know why OnPaint is spammed by the system? Have been staring at this code for ages and I just can't find it.
The CPaintDC destructor has to be called for the repainting flag to be reset. You need to call beginPaint(); and endPaint(); on your CDC which should actually be changed to a CPaintDC. More importantly, not calling endPaint(); will cause the context to be repainted no matter what.
A WM_PAINT message is generated whenever there are no other messages in the message queue and the window's update region (see InvalidateRect) is non-empty. When handling a WM_PAINT message an application signals that the update region has been repainted by calling EndPaint. Failing to call EndPaint will not mark the update region as handled, so the next time an application asks for a message, WM_PAINT is a valid candidate.
In MFC the functionality to call BeginPaint and EndPaint is encapsulated in the CPaintDC Class. The standard MFC message handler for WM_PAINT looks like this:
void OnPaint()
{
CPaintDC dc(this); // calls BeginPaint()
// Perform rendering operations on dc
// ...
} // CPaintDC::~CPaintDC() calls EndPaint()
More detailed information on using device contexts can be found at Device Contexts.

Browse For Folder dialog window handle C++

How to get the handle HWND of the dialog which user open when clicking on a button.
I'm using Spy++ to find the window class and tittle, but it says that no such window is found. And how then to get the handle of that dialog in C++ using Win API ?
I hope that I will be able to do that using simple functions as FindWindow, GetParent, any WIN APi function. I do not like to inject something or load DLL. Thanks
UPDATE:
the folder browser dialog is opened by other program. I want to get it's handle from different program , my program. Thanks.
The closest to want i need is for now the function WindowFromPoint
Accessibility will let you capture window creation events from other processes without DLL injection. You can modify the example to accommodate for the browsing window specifically. Here's an example I made previously to test that is based on the one from the article. Modify it however you wish:
#include <iostream>
#include <windows.h>
void CALLBACK proc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG obj, LONG child, DWORD thr, DWORD time) {
if (hwnd && obj == OBJID_WINDOW && child == CHILDID_SELF) {
switch (event) {
case EVENT_OBJECT_CREATE: {
std::cout << "Window created!\n";
break;
}
case EVENT_OBJECT_DESTROY: {
std::cout << "Window destroyed!\n";
break;
}
}
}
}
int main() {
HWINEVENTHOOK hook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY, nullptr, proc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (hook) {
UnhookWinEvent(hook);
}
}