Click here to Skip to main content
15,881,172 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hello Everyone,

I am trying to figure out the exact reason for the crash happening in my 32 bit MFC application which is running on 64 bit system.
Actually this is a multithreaded MFC SDI application and can do cyclic execution which includes Inspection and outputting inspection results as reports.

After an inspection finishes it show a Custom Alert Window with a progress control until the reports are generated.The Alert Window is created from a Worker Thread and the Main Thread waits until the window is created.

Below is the coded representation of one cycle of Displaying the Alert Window With Progress Bar:

C++
static const __int64     POPUPWND_POLLPERIOD = 10 * 10000LL;
static const __int64     POPUPWND_POLLTIMEOUT = 1000 * POPUPWND_POLLPERIOD;

class CCallFunc
{
public:
	class Queue;

public:
	typedef int(*Call)(const CCallFunc &cf);

public:
	CCallFunc(Call call, LPVOID lpData) :
		m_call(call),
		m_lpData(lpData)
	{}

	int Run() { m_call(*this); }

	LPVOID GetData() const { return m_lpData; }

private:
	Call	m_call;
	LPVOID	m_lpData;
};

class CCallFunc::Queue
{
public:
	int SetQueue(const CCallFunc &cf, const __int64 &timeout = INFINITE)
	{
		m_pcf = &cf;
		m_timeout = timeout;
	}

public:
	int Run(const __int64 &timeout = 0)
	{
		CCallFunc	cf(*m_pcf);

		cf.Run();
	}

private:
	const CCallFunc*	m_pcf;
	__int64			m_timeout;
};


class CWorkThread
{
private:
	static DWORD WINAPI SystemThread(LPVOID lpData)
	{
		CWorkThread*	pThread = (CWorkThread*)lpData;
		__int64			timeout = pThread->m_timeout;

		try {
			pThread->m_queue.Run(timeout);
		}
		catch (const CCallFunc &cf) {
			pThread->m_queue.SetQueue(cf, timeout);
		}
	}

public:
	static int Aquire(CWorkThread *pThread)
	{
		pThread = &thisThread;

		return S_OK;
	}

	static void Sleep(const __int64 &period)
	{
		__int64 current;
		__int64	final = period;

		switch (final) {
		case INFINITE:
			while (true)
				::SleepEx(INFINITE, TRUE);
			throw;

		case 0:
			::SleepEx(DWORD(0), TRUE);
			return;

		default:
			::GetSystemTimeAsFileTime(reinterpret_cast<FILETIME*>(¤t));
			if ((final += current) < 0)
				final = current;

			while (current < final) {
				if (::SleepEx(DWORD((final - current) / __int64(10000)), TRUE) == 0)
					return;

				::GetSystemTimeAsFileTime((FILETIME*)¤t);
			}
		}
	}

	int Start(CCallFunc::Call call, LPVOID lpData)
	{
		return Start(CCallFunc(call, lpData));
	}

	int Start(const CCallFunc &fc)
	{
		DWORD dwID = 0;

		::CreateThread(0, 0, &SystemThread, this, 0, &dwID);
	}

public:
	CCallFunc::Queue m_queue;

private:
	__int64 m_timeout;

	static CWorkThread thisThread;
};

class CPopupWindow;

struct PopupWndCreateContext : public CCreateContext {
	CPopupWindow*	popup;
	CString			clsname;
	CString			wndname;
	DWORD			style;
	DWORD			exstyle;
	CRect			rc;
	HWND			parent;
	UINT			id;
};


class CPopupWindow : public CWnd
{
public:
	int Show()
	{
		HWND        hParent = 0;
		CWinApp*	pApp = NULL;
		CWnd*		pMain;

		if ((pApp = ::AfxGetApp()) != 0 && (pMain = pApp->GetMainWnd()) != 0) {
			hParent = pMain->m_hWnd;
		}

		Create(800, 600, hParent);
	}

private:
	int Create(int iWidth, int iHeight, HWND parent)
	{
		PopupWndCreateContext ctxt;

		ctxt.popup = this;
		ctxt.clsname = "AlertCtrl";
		ctxt.wndname = "Alert Control";
		ctxt.style = WS_VISIBLE | WS_POPUP;
		ctxt.exstyle = 0;
		ctxt.rc = CRect(0, 0, iWidth, iHeight);

		ctxt.parent = parent;
		ctxt.id = 10000;

		CWorkThread* pThread;
		int			e;

		if (SUCCEEDED(e = CWorkThread::Aquire(pThread)) && SUCCEEDED(e = pThread->Start(&Run, &ctxt))) {

			for (__int64 t = 0; t < POPUPWND_POLLTIMEOUT; t += POPUPWND_POLLPERIOD) {
				if (::IsWindow(*this))
					return 0;
				CWorkThread::Sleep(POPUPWND_POLLPERIOD);
			}
		}
	}

	static int Run(const CCallFunc &cf)
	{
		int						e = 0;
		PopupWndCreateContext&	ctxt = *(static_cast<PopupWndCreateContext*>(cf.GetData()));

		ASSERT(&ctxt != 0);

		CPopupWindow    &wnd = *ctxt.popup;

		static const DWORD   clsstyle = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW;
		static const HCURSOR clscursor = ::LoadCursor(0, IDC_WAIT);
		static const HICON   clsicon = 0;
		static LPCTSTR       clsname = ::AfxRegisterWndClass(clsstyle, clscursor, NULL, clsicon);

		if (wnd.CreateEx(DWORD(ctxt.exstyle), ctxt.clsname, ctxt.wndname, DWORD(ctxt.style), ctxt.rc.left, ctxt.rc.top, ctxt.rc.Width(), ctxt.rc.Height(), ctxt.parent, HMENU(ctxt.id), 0) != 0) {
			HWND              hwnd = wnd.GetSafeHwnd();

			::UpdateWindow(hwnd);

			MSG               msg;
			while ((::GetMessage(&msg, 0, 0, 0))) {

				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}

			wnd.DestroyWindow();

		}
		return e;

	}
};


class CAlertCtrl : CPopupWindow
{
	CProgressCtrl m_progctrl;

	DECLARE_MESSAGE_MAP();

	int OnCreate(LPCREATESTRUCT cs)
	{
		int	e = 0;                     //< error code / return value
		if ((e = __super::OnCreate(cs)) != 0)
			return e;

		if (!::IsWindow(m_progctrl))
		{
			CRect rc;

			GetClientRect(rc);
			if (m_progctrl.Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH, rc, this, 100000))
				m_progctrl.SetRange(0, 10000);
		}

		return e;
	}
};


BEGIN_MESSAGE_MAP(CAlertCtrl, CPopupWindow)
	ON_WM_CREATE()
END_MESSAGE_MAP()


So while executing m_progctrl.Create it crashes in the Wincore.cpp
at the method CWnd::DefWindowProc trying to execute callWindowProc after calling the method CPopupWindow::Show for the 35th Cycle.

C++
/////////////////////////////////////////////////////////////////////////////
// Default CWnd implementation

LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	if (m_pfnSuper != NULL)
		return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam);
Posted
Updated 15-Oct-14 18:58pm
v3
Comments
Richard MacCutchan 14-Oct-14 11:18am    
Why are you not using the built in templates and classes provided by MFC? Since these classes are all your own there may be bugs anywhere.
manu goel 15-Oct-14 1:16am    
Hi Richard,

Actually its not the code that i Wrote. It was already written by another team.
The code that you see here is just the representation of the same code with only relevant Methods, Members and procedure.
[no name] 14-Oct-14 12:02pm    
Why this function? It has a parameter "fc" that is not used.

int Start(const CCallFunc &fc)

FYI - any time your design requires "IsWindow", you've probably done something wrong.
manu goel 15-Oct-14 1:19am    
Hi Bling,

As its just the representation of the Relevant actual Code. The parameter "fc" is actually used in that method, but is not relevant for us in this situation.

Also the Main Thread waits for the Alert Window to get Created thats why they have used IsWindow
[no name] 15-Oct-14 12:48pm    
As Richard points out, you've omitted much. It is hard to tell what's going on. This probably exceeds the scope for "Quick Answers".

Here's a very safe design.

Don't create the popup dialog on the inspection thread.

Create the popup dialog on the UI thread.

The inspection thread can call PostMessage to pass results and progress back to the UI thread.
 
Share this answer
 
Comments
manu goel 14-Oct-14 13:24pm    
Hi Bling,

Thanks, but note that it doesn't happen everytime but the 35th time as it's an indefinite cyclic inspection in that same procedure happens again and again so the Alert Window with the progress bar also gets created after one cycle of inspection finishes while the reports gets written to disk.

Also as the Inspection application is a Regular Dll MFC which eventually Creates the Object of Type CAlertCtrl and then calls the Show Method so there i can get the main window using ::AfxGetApp()->m_pMainWnd and post a message to the main window to create the Alert Control.
Sorry Everyone,

Just forgot to mention that my application is 32 bit which is running on 64 bit windows where this crash happens.

While on 32 bit Windows this crash never happens.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900