Click here to Skip to main content
15,893,814 members
Articles / Desktop Programming / MFC

Background Task Dialog

Rate me:
Please Sign up or sign in to vote.
3.55/5 (6 votes)
19 Apr 2004CPOL1 min read 122.5K   2.3K   21  
A wrapper for dialog boxes where you must do a long-time process but you don't want your application to appear to be HUNG.
// BackgroundTaskDialog.cpp : implementation file
//

#include "stdafx.h"
#include "BackgroundTaskDialog.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////

static UINT RunBackgroundTaskProc(LPVOID pParam);

/////////////////////////////////////////////////////////////////////////////
// CBackgroundTaskDialog dialog

CBackgroundTaskDialog::CBackgroundTaskDialog(UINT nIDD, CWnd* pParent /*=NULL*/)
	: CDialog(nIDD, pParent)
{
	//{{AFX_DATA_INIT(CBackgroundTaskDialog)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	hKillBackgroundThreadEvent = hDoneBackgroundThreadEvent = NULL;
	lpBackgroundThread = NULL;
	return;
}

CBackgroundTaskDialog::~CBackgroundTaskDialog()
{
	StopBackgroundTask();
	return;
}

void CBackgroundTaskDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CBackgroundTaskDialog)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CBackgroundTaskDialog, CDialog)
	//{{AFX_MSG_MAP(CBackgroundTaskDialog)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

int CBackgroundTaskDialog::StartBackgroundTask()
{
	if (lpBackgroundThread != NULL) {
		if (IsBackgroundTaskRunning() != FALSE)
			return -1;
		//If the thread has ended call StopBackgroundTask in order
		//to cleanup some stuff
		StopBackgroundTask();
	}
	//create kill thread event
	hKillBackgroundThreadEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
	if (hKillBackgroundThreadEvent == NULL)
		return -2;
	//create work-done thread event
	hDoneBackgroundThreadEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
	if (hDoneBackgroundThreadEvent == NULL) {
		::CloseHandle(hKillBackgroundThreadEvent);
		hKillBackgroundThreadEvent = NULL;
		return -3;
	}
	//create thread itself
	lpBackgroundThread = AfxBeginThread(RunBackgroundTaskProc, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
	if (lpBackgroundThread == NULL) {
		::CloseHandle(hDoneBackgroundThreadEvent);
		hDoneBackgroundThreadEvent = NULL;
		::CloseHandle(hKillBackgroundThreadEvent);
		hKillBackgroundThreadEvent = NULL;
		return -4;
	}
	lpBackgroundThread->m_bAutoDelete = FALSE;
	//resume thread
	::ResumeThread(lpBackgroundThread->m_hThread);
	return 1;
}

int CBackgroundTaskDialog::StopBackgroundTask(int nTimeOut)
{
	MSG msg;
	DWORD dwExitCode;
	int tim, nTimeCounter;

	if (lpBackgroundThread == NULL)
		return -1;
	//I dont know why sometimes finished threads don't get signalled
	if ((::WaitForSingleObject(hDoneBackgroundThreadEvent, 0) != WAIT_OBJECT_0) &&
		  (::GetExitCodeThread(lpBackgroundThread->m_hThread, &dwExitCode) && dwExitCode==STILL_ACTIVE)) {
	  //thread is still active...
		//send kill event
		::SetEvent(hKillBackgroundThreadEvent);
		//wait for thread completion
		for (nTimeCounter=nTimeOut;;) {
			if (nTimeOut > 0) {
				if ((tim = nTimeCounter) > 100)
					tim = 100;
			}
			else
				tim = 0;
			if (::WaitForSingleObject(hDoneBackgroundThreadEvent, tim) == WAIT_OBJECT_0)
				break;
			if (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE) != 0) {
				if (AfxGetThread()->PumpMessage() == FALSE) {
					::TerminateThread(lpBackgroundThread->m_hThread, 0);
					::PostQuitMessage(msg.wParam);
					break;
				}
			}
			if (::GetExitCodeThread(lpBackgroundThread->m_hThread, &dwExitCode) && dwExitCode!=STILL_ACTIVE)
				break;
			if (nTimeOut > 0) {
				if ((nTimeCounter -= tim) == 0) {
					::TerminateThread(lpBackgroundThread->m_hThread, 0);
					break;
				}
			}
		}
	}
	//cleanup
	if (lpBackgroundThread != NULL) {
		delete lpBackgroundThread;
		lpBackgroundThread = NULL;
	}
	if (hDoneBackgroundThreadEvent != NULL) {
		::CloseHandle(hDoneBackgroundThreadEvent);
		hDoneBackgroundThreadEvent = NULL;
	}
	if (hKillBackgroundThreadEvent != NULL) {
		::CloseHandle(hKillBackgroundThreadEvent);
		hKillBackgroundThreadEvent = NULL;
	}
	return 1;
}

BOOL CBackgroundTaskDialog::CheckForBackgroundTaskAbort()
{
	if (lpBackgroundThread == NULL)
		return TRUE;
	if (::WaitForSingleObject(hKillBackgroundThreadEvent, 0) == WAIT_OBJECT_0)
		return TRUE;
	return FALSE;
}

BOOL CBackgroundTaskDialog::IsBackgroundTaskRunning()
{
	DWORD dwExitCode;

	if (lpBackgroundThread == NULL)
		return FALSE;
	if (::WaitForSingleObject(hDoneBackgroundThreadEvent, 0) == WAIT_OBJECT_0)
		return FALSE;
	if (::GetExitCodeThread(lpBackgroundThread->m_hThread, &dwExitCode) && dwExitCode!=STILL_ACTIVE)
		return FALSE;
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// OVERRIDABLES

void CBackgroundTaskDialog::RunBackgroundTask()
{
	return;
}

/////////////////////////////////////////////////////////////////////////////
// INTERNAL FUNCTIONS

static UINT RunBackgroundTaskProc(LPVOID pParam)
{
	CBackgroundTaskDialog *bt_dlg;

	bt_dlg = (CBackgroundTaskDialog*)pParam;
	bt_dlg->RunBackgroundTask();
	::SetEvent(bt_dlg->hDoneBackgroundThreadEvent);
	return 1;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Web Developer
Argentina Argentina
My name is Mauro Leggieri. I am 30 year-old, married and have a child.

I am a system engineer (UTN university) and am being programming for more than 20 years from the C64 to the PC and some microcontrollers.

Mostly of my time, I program games for Windows.

Soon, my site http://www.mauroleggieri.com.ar

Comments and Discussions