1

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:

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*>(&current));
            if ((final += current) < 0)
                final = current;

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

                ::GetSystemTimeAsFileTime((FILETIME*)&current);
            }
        }
    }

    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.

/////////////////////////////////////////////////////////////////////////////
// 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);
  • There's a lot of code to eyeball there, but one thing I noticed is that you're using `CreateThread` instead of `AfxBeginThread`, which will not initialise MFC's multithreading support. It would be ok if the worker thread is not using MFC objects, but without more time to look ..... – Roger Rowland Oct 14 '14 at 13:55
  • Hi @RogerRowland 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. – user3250220 Oct 15 '14 at 05:32
  • Nevertheless, if you're using MFC objects in a background thread, you *must* use `AfxBeginThread`. The problems can be intermittent and subtle because idle processing is used to do some things like releasing temporary handle maps, so it can appear to work ok for a while before crashing. In any case, it's a small change and probably worth testing to eliminate it as a possible source of errors. – Roger Rowland Oct 15 '14 at 06:25

0 Answers0