// MultiThread.h : header file
// Copyright (C) 1997 by The Windward Group, All Rights Reserved
#ifndef MULTITHREAD_H
#define MULTITHREAD_H
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include <afxmt.h>
/////////////////////////////////////////////////////////////////////////////
class CMultiThread : public CWinThread
{
DECLARE_DYNCREATE(CMultiThread)
public:
CMultiThread();
virtual ~CMultiThread();
BOOL CreateThread(DWORD dwCreateFlags = 0, // masks
// CWinThread::CreateThread
UINT nStackSize = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL,
UINT nMilliSecs = INFINITE); // upper time limit to wait
BOOL InitInstance() {return TRUE;}
void KillThread2();
int Run();
protected:
CEvent* m_pWorkEvent; // do work event
CEvent* m_pExitEvent; // used to synchronize destruction
int m_nCycleTime; // do work cycle time
BOOL m_bEndThread; // end the thread ?
virtual void StartWork() {} // override to do startup
virtual void DoWork() {} // override to do work
virtual void EndWork() {} // override to do shutdown
CEvent* GetEvent() const {return m_pWorkEvent;} // cycle control event
int GetCycleTime() const {return m_nCycleTime;}
void SetCycleTime(int nMilliSecs) {m_nCycleTime = nMilliSecs;}
};
#endif
// MultiThread.cpp : implementation file
// Copyright (C) 1997 by The Windward Group, All Rights Reserved
#include "stdafx.h"
#include "MultiThread.h"
IMPLEMENT_DYNCREATE(CMultiThread, CWinThread)
/////////////////////////////////////////////////////////////////////////////
// CMultiThread
CMultiThread::CMultiThread()
{
// Create a non-signaled, manual-reset event to synchronize destruction
m_pExitEvent = new CEvent(FALSE, TRUE);
ASSERT(m_pExitEvent);
// Create a non-signaled, auto-reset event to wait on for work cycle
m_pWorkEvent = new CEvent();
ASSERT(m_pWorkEvent);
}
CMultiThread::~CMultiThread()
{
delete m_pWorkEvent;
delete m_pExitEvent;
}
BOOL CMultiThread::CreateThread(DWORD dwCreateFlags, UINT nStackSize,
LPSECURITY_ATTRIBUTES lpSecurityAttrs,
UINT nMilliSecs)
{
m_nCycleTime = nMilliSecs;
m_bEndThread = FALSE;
// Start second thread
return CWinThread::CreateThread(dwCreateFlags, nStackSize, lpSecurityAttrs);
}
void CMultiThread::KillThread2()
{
// Start up the other thread so it can complete.
// When it does, it will set the exit event and the object can be destructed.
m_bEndThread = TRUE;
m_pWorkEvent->SetEvent();
CSingleLock csl(m_pExitEvent);
csl.Lock(); // wait for 2nd thread to finish
csl.Unlock();
}
int CMultiThread::Run()
{
CSingleLock csl(m_pWorkEvent); // synch on the work event
StartWork(); // do derived startup
while (!m_bEndThread) // loop until we're done
{
csl.Lock(m_nCycleTime); // wait for event or timeout
csl.Unlock();
if (!m_bEndThread) DoWork(); // and then do some work
}
EndWork(); // do derived shutdown
m_pExitEvent->SetEvent(); // set not waiting signal
AfxEndThread(0, FALSE); // end the thread, but do not delete it
return 0;
}
Figure 3 CThinThread
// ThinThread.h : header file
// Copyright (C) 1997 by The Windward Group, All Rights Reserved
#ifndef THINTHREAD_H
#define THINTHREAD_H
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include <afxmt.h>
/////////////////////////////////////////////////////////////////////////////
class CThinThread
{
public:
CThinThread();
virtual ~CThinThread();
BOOL CreateThread(DWORD dwCreateFlags = 0,
UINT nStackSize = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL,
UINT nMilliSecs = INFINITE); // upper time limit to wait
HANDLE GetHandle() {return m_hThread2;}
BOOL IsBusy() {return m_b2ndThread;}
void Stop() {m_bEndThread = TRUE;}
protected:
CEvent* m_pWorkEvent; // do work event
CEvent* m_pExitEvent; // used to synchronize destruction
int m_nCycleTime; // do work cycle time
BOOL m_bEndThread; // end the thread ?
BOOL m_b2ndThread; // 2nd thread active?
HANDLE m_hThread2; // 2nd thread handle
virtual void StartWork() {} // override to do startup
virtual void DoWork() = 0; // override to do work
virtual void EndWork() {} // override to do shutdown
CEvent* GetEvent() const {return m_pWorkEvent;} // cycle control event
int GetCycleTime() const {return m_nCycleTime;}
void KillThread2();
int Run();
void SetCycleTime(int nMilliSecs) {m_nCycleTime = nMilliSecs;}
static unsigned int __stdcall Start(void* pv);
};
#endif
// ThinThread.cpp : implementation file
// Copyright (C) 1997 by The Windward Group, All Rights Reserved
#include "stdafx.h"
#include "ThinThread.h"
#include <process.h> /* _beginthread, _endthread */
/////////////////////////////////////////////////////////////////////////////
// ThinThread
CThinThread::CThinThread()
: m_b2ndThread(FALSE)
{
// Create a signaled, manual-reset event to synchronize destruction
m_pExitEvent = new CEvent(TRUE, TRUE);
ASSERT(m_pExitEvent);
// Create a non-signaled, auto-reset event to wait on for work cycle
m_pWorkEvent = new CEvent();
ASSERT(m_pWorkEvent);
}
BOOL CThinThread::CreateThread(DWORD dwCreateFlags, UINT nStackSize,
LPSECURITY_ATTRIBUTES lpSecurityAttrs,
UINT nMilliSecs)
{
m_b2ndThread = TRUE;
m_bEndThread = FALSE;
m_nCycleTime = nMilliSecs;
m_pExitEvent->ResetEvent(); // exit event is reset until we're done
// Start second thread
unsigned usThreadAddr;
m_hThread2 = reinterpret_cast<HANDLE>
(_beginthreadex(lpSecurityAttrs, nStackSize, Start,
this, 1, &usThreadAddr));
return reinterpret_cast<unsigned long> (m_hThread2);
}
CThinThread::~CThinThread()
{
delete m_pWorkEvent;
delete m_pExitEvent;
}
void CThinThread::KillThread2()
{
// Start up the other thread so it can complete.
// When it does, it will set the exit event and the object can
// be destructed.
m_bEndThread = TRUE;
m_pWorkEvent->SetEvent();
CSingleLock csl(m_pExitEvent);
csl.Lock(); // wait for 2nd thread to finish
csl.Unlock();
}
int CThinThread::Run()
{
CSingleLock csl(m_pWorkEvent); // synch on the work event
StartWork(); // do derived startup
while (!m_bEndThread) // loop until we're done
{
csl.Lock(m_nCycleTime); // wait for event or timeout
csl.Unlock();
if (!m_bEndThread) DoWork(); // then do derived work
}
EndWork(); // do derived shutdown
m_pExitEvent->SetEvent(); // set not waiting signal
m_b2ndThread = FALSE;
CloseHandle(m_hThread2);
_endthreadex(0);
return 0;
}
unsigned int __stdcall CThinThread::Start(void* pv)
{
CThinThread* pMT = static_cast<CThinThread*> (pv);
return pMT->Run();
}
Figure 5 CrefreshThread
// RefreshThread.h : header file
// Copyright (C) 1996 by CTB/McGraw-Hill, All Rights Reserved
#ifndef REFRESHTHREAD_H
#define REFRESHTHREAD_H
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include <afxmt.h>
#include "ThinThread.h"
#include "ListCtrlEx.h"
#include "OpUnitStatusMgrInc.h"
using namespace OpUnitStatusRecordSQLParts;
#include "PageBase.h"
/////////////////////////////////////////////////////////////////////////////
class CRefreshThread : public CThinThread, public CPageBase
{
public:
CRefreshThread() {};
virtual ~CRefreshThread() {KillThread2();}
BOOL Go();
void Set(HWND hActive, HWND hHistory,
const CString& csFilter,
const CUIntArray& sortFields, BOOL bActive=TRUE);
protected:
HWND m_hwndActive;
HWND m_hwndHistory;
CString m_csFilter;
CUIntArray m_cuiaSortFields;
BOOL m_bActiveTable;
CListCtrlEx m_LCActive;
CListCtrlEx m_LCHistory;
OURecSet* m_pRecSet;
int m_nRecord;
virtual void StartWork(); // start work
virtual void DoWork(); // continue doing work
virtual void EndWork(); // end work
};
#endif
// RefreshThread.cpp : implementation file
// Copyright (C) 1997 by CTB/McGraw-Hill, All Rights Reserved
#include "stdafx.h"
#include "RefreshThread.h"
/////////////////////////////////////////////////////////////////////////////
// CRefreshThread
void CRefreshThread::Set(HWND hActive, HWND hHistory, const CString& csFilter,
const CUIntArray& sortFields, BOOL bActive)
{
m_hwndActive = hActive;
m_hwndHistory = hHistory;
m_csFilter = csFilter;
m_bActiveTable = bActive;
m_nRecord = 0;
int size = sortFields.GetSize();
m_cuiaSortFields.SetSize(size);
for (int i = 0; i < size; i++)
m_cuiaSortFields.SetAt(i, sortFields.GetAt(i));
}
BOOL CRefreshThread::Go()
{
// kick off CThinThread with no loop delay
return CreateThread(0, 0, NULL, 0);
}
void CRefreshThread::StartWork()
{
// setup the listctrls
m_LCActive.Attach(m_hwndActive);
m_LCHistory.Attach(m_hwndHistory);
m_LCActive.DeleteAllItems();
m_LCHistory.DeleteAllItems();
m_pRecSet = m_pStatMgr->GetAllOrderedRecords((m_bActiveTable ?
COpUnitStatusMgr::TABLE_ACTIVE : COpUnitStatusMgr::TABLE_ARCHIVED),
m_cuiaSortFields, m_csFilter, FALSE, TRUE);
// prepare the list control to consume mass quantities
m_LCActive.SetItemCount(m_pRecSet->GetRecordCount());
// insert the data from first database record directly into the list control
if (m_pRecSet && m_pRecSet->GetFirstRecord(m_nRecord++, &m_LCActive));
else m_bEndThread = TRUE;
}
void CRefreshThread::DoWork()
{
if (!m_pRecSet->GetNextRecord(m_nRecord++, &m_LCActive))
m_bEndThread = TRUE;
}
void CRefreshThread::EndWork()
{
// release the record set
m_pSPCSFactory->ReleaseOpUnitStatusRecordSet(m_pRecSet);
// select first, repaint, and set focus
SelectFirstItem(m_LCActive);
UpdatesCompleted(m_LCActive, m_LCHistory);
// cleanup the listctrls
m_LCActive.Detach();
m_LCHistory.Detach();
}
Figure 6 CjobMgrImp
// JobMgrImp.cpp : implementation file
// Copyright (C) 1997 by CTB/McGraw-Hill, All Rights Reserved
/////////////////////////////////////////////////////////////////////////////
// internal thread step methods
/////////////////////////////////////////////////////////////////////////////
// do the operation
BOOL CJobMgrImp::DoTheOp()
{
BOOL bRet = FALSE;
if (SetParameters()) // set values in the shared parameter file
{
if (m_OpVals.bLocalOp)
{ // local operations
if (m_LocalOp.DoFunction(m_csIOFile))
{ if (GetParameters()) bRet = TRUE;}
else m_csError = errCreateProc;
}
else if (m_OpVals.csOp.GetLength())
{ // other operations
STARTUPINFO si;
PROCESS_INFORMATION pi;
si.cb = sizeof(STARTUPINFO);
si.lpReserved = NULL;
si.lpDesktop = NULL;
si.lpTitle = NULL;
si.dwFlags = 0;
si.cbReserved2 = 0;
si.lpReserved2 = NULL;
if (CreateProcess(NULL,
(LPTSTR)(LPCTSTR)(m_OpVals.csOp + CString(" ") + m_csIOFile),
NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED)
{
if (GetParameters())
bRet = TRUE;
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else m_csError = errWaitProc;
}
else m_csError = errCreateProc;
}
else bRet = TRUE; // no operation
}
else m_csError = errParamFile;
TraceWork();
return bRet;
}
Figure 8 ClaunchThread
// LaunchThread.h : header file
// Copyright (C) 1997 by CTB/McGraw-Hill, All Rights Reserved
#ifndef LAUNCHTHREAD_H
#define LAUNCHTHREAD_H
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include <afxmt.h>
#include "ThinThread.h"
#include "ListCtrlEx.h"
#include "OpUnitStatusMgrInc.h"
using namespace OpUnitStatusRecordSQLParts;
#include "PageBase.h"
/////////////////////////////////////////////////////////////////////////////
class CLaunchThread : public CThinThread, public CPageBase
{
public:
CLaunchThread() {};
virtual ~CLaunchThread(){KillThread2();}
BOOL Go();
void Set(HWND hParent, HWND hList, HCURSOR hc,
const CString& csLaunchee, const CString& csOpUnit);
protected:
HWND m_hwndParent;
HWND m_hwndList;
HCURSOR m_hCursor;
CString m_csLaunchee;
CString m_csOpUnit;
CListCtrlEx m_LC;
virtual void DoWork(); // do the work
};
#endif
// LaunchThread.cpp : implementation file
// Copyright (C) 1997 by CTB/McGraw-Hill, All Rights Reserved
#include "stdafx.h"
#include "LaunchThread.h"
/////////////////////////////////////////////////////////////////////////////
// CLaunchThread
void CLaunchThread::Set(HWND hParent, HWND hList, HCURSOR hc,
const CString& csLaunchee, const CString& csOpUnit)
{
m_hwndParent = hParent;
m_hwndList = hList;
m_hCursor = hc;
m_csLaunchee = csLaunchee;
m_csOpUnit = csOpUnit;
}
BOOL CLaunchThread::Go()
{
// kick off CThinThread with no loop delay
return CreateThread(0, 0, NULL, 0);
}
void CLaunchThread::DoWork()
{
CString csResult = LaunchApp(m_csLaunchee, m_csOpUnit, m_hCursor);
if (csResult.GetLength())
{
SetActiveState(csResult, m_csOpUnit);
CListCtrlEx list;
list.Attach(m_hwndList);
SelectItemRow(list, 0, m_csOpUnit);
list.Detach();
}
PostMessage(m_hwndParent, WM_COMMAND, (csResult.GetLength() ? 1 : 0),
reinterpret_cast<int> (this));
m_bEndThread = TRUE;
}
void CUpdatesPage::OnBegin()
{
HCURSOR hCursorOld = SetCursor(AfxGetApp()->LoadCursor(IDC_PLEASEWAIT));
// get selected OpUnit
int row = m_lcOpUnitInfo.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
if (row > -1)
{
CString csOpUnit = m_lcOpUnitInfo.GetItemText(row, UC_ORGTP);
csOpUnit += ",";
csOpUnit += m_lcOpUnitInfo.GetItemText(row, UC_STRUCTUREELEMENT);
csOpUnit += ",";
csOpUnit += m_lcOpUnitInfo.GetItemText(row, UC_OPUNIT);
// launch the app
m_iLaunchCount++;
CLaunchThread* pThread = new CLaunchThread;
pThread->Set(GetSafeHwnd(), m_lcOpUnitInfo.GetSafeHwnd(), hCursorOld,
pLaunchName, csOpUnit);
pThread->Go();
m_lcOpUnitInfo.SetFocus();
}
}
// launch a Winscore app
CString CPageBase::LaunchApp(const CString& csAppName,
const CString& csOpUnit, HCURSOR hCursor)
{
CString csRet = "";
CParamFile file;
SOutputStrings strOut;
if (csAppName.GetLength() && SetParameters(&file, csOpUnit))
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
si.cb = sizeof(STARTUPINFO);
si.lpReserved = NULL;
si.lpDesktop = NULL;
si.lpTitle = NULL;
si.dwFlags = 0;
si.cbReserved2 = 0;
si.lpReserved2 = NULL;
if (CreateProcess(NULL,
(LPTSTR)(LPCTSTR)(csAppName + CString(" ") + file.GetName()),
NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
Sleep(3000); // to show launch cursor
SetCursor(hCursor);
if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED)
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
file.GetOutputStrings(strOut);
strOut.csStatus.MakeLower();
if (strOut.csStatus == fpvSuccess)
csRet = CParamFile::Code2String(strOut.csRet1);
}
}
else SetCursor(hCursor);
}
Sleep(1000); // to wait for completion of file usage
CKeyValues key;
if (key.GetRemoveParamFile()) file.Remove();
return csRet;
}
BOOL CUpdatesPage::OnCommand(WPARAM wParam, LPARAM lParam)
{
if (wParam > 1)
{ // message not sent by CLaunchThread
CPropertyPage::OnCommand(wParam, lParam);
return 0;
}
// message sent by CLaunchThread
LaunchDone(!wParam ? pLaunchName : "", lParam);
m_iLaunchCount--;
m_lcOpUnitInfo.SetFocus();
return CPropertyPage::OnCommand(0, lParam);
}
// launch completion handler
void CPageBase::LaunchDone(const CString& csAppName, LPARAM lParam)
{
if (csAppName.GetLength()) AfxMessageBox(pLaunchText + csAppName);
delete (reinterpret_cast<CLaunchThread*> (lParam));
}
BOOL CSpcsView::CheckThreads()
{
BOOL bRet = TRUE;
CRefreshThread* pThread1 = m_pPropSheet->GetStatusPage()->GetThread();
CRefreshThread* pThread2 = m_pPropSheet->GetOfflinePage()->GetThread();
if (pThread1->IsBusy() || pThread2->IsBusy() ||
m_pPropSheet->GetUpdatesPage()->IsLaunchActive() ||
m_pPropSheet->GetBrowserPage()->IsLaunchActive() ||
m_pPropSheet->GetReaderPage()->IsLaunchActive()) bRet = FALSE;
return bRet;
}
Figure 9 CRequestHandlerThread and CrequestPacket
// HandlerThread.h : header file
// Copyright (C) 1997 by The Windward Group, All Rights Reserved
#ifndef HANDLERTHREAD_H
#define HANDLERTHREAD _H
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include <afxmt.h>
#include "ThinThread.h"
/////////////////////////////////////////////////////////////////////////////
class CRequestPacket : public CObject
{
public:
int m_iPacketType;
int m_iStatus;
CString m_csInput;
CString m_csOutput;
};
/////////////////////////////////////////////////////////////////////////////
class CRequestHandlerThread : public CThinThread
{
public:
CRequestHandlerThread() {};
virtual ~CRequestHandlerThread() {KillThread2();}
void AddRequest(CRequestPacket* pPkt);
BOOL Go() {return CreateThread(0, 0, NULL, 0);}
void Set(HWND hParent, int ID);
protected:
HWND m_hwndParent;
int m_ID;
CObList m_PktList;
CCriticalSection m_CritSect;
virtual void DoWork(); // do the work
virtual void CheckInput() = 0; // check packet input
virtual void RetrieveData() = 0; // get required data
virtual void ProcessData() = 0; // process the data
virtual void UpdateState() = 0; // update any state info
virtual void LoadOutput() = 0; // load packet output
};
#endif
// HandlerThread.cpp : implementation file
// Copyright (C) 1997 by The Windward Group, All Rights Reserved
#include "stdafx.h"
#include "HandlerThread.h"
/////////////////////////////////////////////////////////////////////////////
// CRequestHandlerThread
void CRequestHandlerThread::Set(HWND hParent, int ID)
{
m_hwndParent = hParent;
m_ID = ID;
}
void CRequestHandlerThread::AddRequest(CRequestPacket* pPkt)
{
CSingleLock csl(&m_CritSect); // be safe
csl.Lock(); // when accessing packet list
m_PktList.AddTail(pPkt); // put the packet on the list
csl.Unlock();
GetEvent()->SetEvent(); // notify internal thread
}
void CRequestHandlerThread::DoWork()
{
while (!m_PktList.IsEmpty()) // get next packet
{
CSingleLock csl(&m_CritSect); // be safe
csl.Lock(); // when accessing packet list
CRequestPacket* pPkt = dynamic_cast<CRequestPacket*>
(m_PktList.RemoveHead());
csl.Unlock();
CheckInput();
RetrieveData();
ProcessData();
UpdateState();
LoadOutput();
// return packet to dispatcher
PostMessage(m_hwndParent, WM_COMMAND,
m_ID, reinterpret_cast<int> (pPkt));
}
}
Figure 10 CfileSearchThread
// SearchThread.h : header file
// Copyright (C) 1997 by The Windward Group, All Rights Reserved
#ifndef SEARCHTHREAD_H
#define SEARCHTHREAD_H
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include <afxmt.h>
#include "ThinThread.h"
/////////////////////////////////////////////////////////////////////////////
class CFileSearchThread : public CThinThread
{
public:
CFileSearchThread() {};
virtual ~CFileSearchThread() {KillThread2();}
BOOL Go() {return CreateThread(0, 0, NULL, 0);}
void Set(HWND hParent, int ID, const CString& csSearchRoot,
const CString& csSearchString);
protected:
HWND m_hwndParent;
int m_ID;
CString m_csSearchRoot;
CString m_csSearchString;
virtual void DoWork(); // do the work
};
#endif
// SearchThread.cpp : implementation file
// Copyright (C) 1997 by The Windward Group, All Rights Reserved
#include "stdafx.h"
#include "SearchThread.h"
#include <direct.h>
/////////////////////////////////////////////////////////////////////////////
// CFileSearchThread
void CFileSearchThread::Set(HWND hParent, int ID, const CString& csSearchRoot,
const CString& csSearchString)
{
m_hwndParent = hParent;
m_ID = ID;
m_csSearchRoot = csSearchRoot;
m_csSearchString = csSearchString;
}
void CFileSearchThread::DoWork()
{
WIN32_FIND_DATA fd;
_chdir(m_csSearchRoot);
HANDLE hnd = FindFirstFile(m_csSearchString, &fd);
if (hnd != INVALID_HANDLE_VALUE)
PostMessage(m_hwndParent, WM_COMMAND,
m_ID, reinterpret_cast<int> (this));
m_bEndThread = TRUE;
}