/******************************************************************************* * * threads.cpp * * implementation of threads classes * * copyright notice: Copyright 1997, Citrix Systems Inc. * Copyright (c) 1998 - 1999 Microsoft Corporation * * $Author: donm $ Don Messerli * * $Log: N:\nt\private\utils\citrix\winutils\winadmin\VCS\threads.cpp $ * * Rev 1.1 26 Aug 1997 19:15:14 donm * bug fixes/changes from WinFrame 1.7 * * Rev 1.0 30 Jul 1997 17:12:44 butchd * Initial revision. * *******************************************************************************/ #include "stdafx.h" #include "winadmin.h" #include "threads.h" #include "led.h" //////////////////////////////////////////////////////////////////////////////// // CThread class construction / destruction, implementation /******************************************************************************* * * CThread - CThread constructor * * ENTRY: * EXIT: * ******************************************************************************/ CThread::CThread() { m_hThread = NULL; m_dwThreadID = 0; } // end CThread::CThread /******************************************************************************* * * ~CThread - CThread destructor * * ENTRY: * EXIT: * ******************************************************************************/ CThread::~CThread() { } // end CThread::~CThread /******************************************************************************* * * operator new - CThread operator override * * ENTRY: * EXIT: * ******************************************************************************/ #if 0 void * CThread::operator new(size_t nSize) { return( ::malloc(nSize) ); } // end CThread::operator new #endif /******************************************************************************* * * operator delete - CThread operator override * * ENTRY: * EXIT: * ******************************************************************************/ #if 0 void CThread::operator delete(void *p) { ::free(p); } // end CThread::operator delete #endif //////////////////////////////////////////////////////////////////////////////// // CThread operations: primary thread /******************************************************************************* * * CreateThread - CThread implementation function * * Class wrapper for the Win32 CreateThread API. * * ENTRY: * EXIT: * ******************************************************************************/ HANDLE CThread::CreateThread( DWORD cbStack, DWORD fdwCreate ) { /* * Simple wrapper for Win32 CreateThread API. */ return( m_hThread = ::CreateThread( NULL, cbStack, ThreadEntryPoint, (LPVOID)this, fdwCreate, &m_dwThreadID ) ); } // end CThread::CreateThread //////////////////////////////////////////////////////////////////////////////// // CThread operations: secondary thread /******************************************************************************* * * ThreadEntryPoint - CThread implementation function * (SECONDARY THREAD) * * ENTRY: * EXIT: * ******************************************************************************/ DWORD __stdcall CThread::ThreadEntryPoint(LPVOID lpParam) { CThread *pThread; DWORD dwResult; /* * (lpParam is actually the 'this' pointer) */ pThread = (CThread*)lpParam; VERIFY(pThread != NULL); /* * Run the thread. */ dwResult = pThread->RunThread(); /* * Return the result. */ return(dwResult); } // end CThread::ThreadEntryPoint //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // CWSStatusThread class construction / destruction, implementation /******************************************************************************* * * CWSStatusThread - CWSStatusThread constructor * * ENTRY: * EXIT: * ******************************************************************************/ CWSStatusThread::CWSStatusThread() { /* * Create the semaphore when the CWSStatusThread object is created and * initialize the m_bExit and m_bResetCounter flags to FALSE. */ VERIFY( m_hWakeUp = CreateSemaphore( NULL, 0, MAX_STATUS_SEMAPHORE_COUNT, NULL ) ); VERIFY( m_hConsumed = CreateSemaphore( NULL, 0, MAX_STATUS_SEMAPHORE_COUNT, NULL ) ); m_bExit = FALSE; } // end CWSStatusThread::CWSStatusThread /******************************************************************************* * * ~CWSStatusThread - CWSStatusThread destructor * * ENTRY: * EXIT: * ******************************************************************************/ CWSStatusThread::~CWSStatusThread() { /* * Close the semaphores when the CWSStatusThread object is destroyed. */ VERIFY( CloseHandle(m_hWakeUp) ); VERIFY( CloseHandle(m_hConsumed) ); } // end CWSStatusThread::~CWSStatusThread /******************************************************************************* * * RunThread - CWSStatusThread secondary thread main function loop * (SECONDARY THREAD) * * ENTRY: * EXIT: * (DWORD) exit status for the secondary thread. * ******************************************************************************/ DWORD CWSStatusThread::RunThread() { /* * Query for PD and WinStation information to initialize dialog with. */ if ( !WSPdQuery() || !WSInfoQuery() ) { /* * We can't query the WinStation information: tell the primary * thread that we've aborted, and exit this thread. */ PostMessage(m_hDlg, WM_STATUSABORT, 0, 0); return(1); } else { /* * Tell the primary thread (modeless dialog window) that we've * got the initial information. */ PostMessage(m_hDlg, WM_STATUSSTART, 0, 0); WaitForSingleObject(m_hConsumed, INFINITE); /* * Always check for exit request each time we wake up and exit * the thread if the exit flag is set. */ if ( m_bExit ) return(0); } /* * Loop till exit requested. */ for ( ; ; ) { /* * Block the thread until time to refresh or we're woken up. */ WaitForSingleObject( m_hWakeUp, ((CWinAdminApp*)AfxGetApp())->GetStatusRefreshTime()); if ( m_bExit ) return(0); /* * Query for WinStation information. */ if ( !WSInfoQuery() || (m_WSInfo.ConnectState == State_Disconnected) ) { /* * Either we can't query the WinStation or it has become * disconnected: tell the primary thread that we've aborted, * and exit this thread. */ PostMessage(m_hDlg, WM_STATUSABORT, 0, 0); return(1); } else { /* * Tell the dialog that we've got some new query information. */ PostMessage(m_hDlg, WM_STATUSREADY, 0, 0); WaitForSingleObject(m_hConsumed, INFINITE); if ( m_bExit ) return(0); } } } // end CWSStatusThread::RunThread //////////////////////////////////////////////////////////////////////////////// // CWSStatusThread operations: primary thread /******************************************************************************* * * SignalWakeUp - CWSStatusThread member function: public operation * * Release the m_hWakeUp semaphore to start another status query. * * ENTRY: * EXIT: * ******************************************************************************/ void CWSStatusThread::SignalWakeUp() { ReleaseSemaphore(m_hWakeUp, 1, NULL); } // end CWSStatusThread::SignalWakeUp /******************************************************************************* * * SignalConsumed - CWSStatusThread member function: public operation * * Release the m_hConsumed semaphore to allow secondary thread to continue * running. * * ENTRY: * EXIT: * ******************************************************************************/ void CWSStatusThread::SignalConsumed() { ReleaseSemaphore( m_hConsumed, 1, NULL ); } // end CWSStatusThread::SignalConsumed /******************************************************************************* * * ExitThread - CWSStatusThread member function: public operation * * Tell the secondary thread to exit and cleanup after. * * ENTRY: * EXIT: * ******************************************************************************/ void CWSStatusThread::ExitThread() { DWORD dwReturnCode; int i; CWaitCursor Nikki; /* * If the thread was not created properly, just delete object and return. */ if ( !m_hThread ) { delete this; return; } /* * Set the m_bExit flag to TRUE and bump both the consumed and wake up * semaphores to cause RunThread() (the thread's main instructon loop) * to exit. */ m_bExit = TRUE; SignalWakeUp(); SignalConsumed(); /* * Wait a while for the thread to exit. */ for ( i = 0, GetExitCodeThread( m_hThread, &dwReturnCode ); (i < MAX_SLEEP_COUNT) && (dwReturnCode == STILL_ACTIVE); i++ ) { Sleep(100); GetExitCodeThread( m_hThread, &dwReturnCode ); } /* * If the thread has still not exited, terminate it. */ if ( dwReturnCode == STILL_ACTIVE ) { TerminateThread( m_hThread, 1 ); #ifdef _DEBUG // TRACE2( "WSSTATUS: Forced Terminate of thread monitoring LogonID %lu after %u 100msec exit waits.\n", // m_LogonId, MAX_SLEEP_COUNT ); #endif } /* * Close the thread handle and delete this CWSStatusThread object */ VERIFY( CloseHandle(m_hThread) ); delete this; } // end CWSStatusThread::ExitThread //////////////////////////////////////////////////////////////////////////////// // CWSStatusThread operations: secondary thread /******************************************************************************* * * WSPdQuery - CWSStatusThread member function: private operation * (SECONDARY THREAD) * * Query the Pd information for the WinStation object referenced by * the m_LogonId member variable. * * ENTRY: * * EXIT: * (BOOL) TRUE if query was sucessful; FALSE otherwise. * ******************************************************************************/ BOOL CWSStatusThread::WSPdQuery() { ULONG ReturnLength; /* * Query the PD information. */ memset( &m_PdConfig, 0, sizeof(PDCONFIG) ); if ( !WinStationQueryInformation( m_hServer, m_LogonId, WinStationPd, &m_PdConfig, sizeof(PDCONFIG), &ReturnLength ) ) goto BadWSQueryInfo; if(!WinStationQueryInformation(m_hServer, m_LogonId, WinStationPd, &m_PdConfig, sizeof(PDCONFIG), &ReturnLength ) ) goto BadWSQueryInfo; return(TRUE); /*-------------------------------------- * Error clean-up and return... */ BadWSQueryInfo: return(FALSE); } // end CWSStatusThread::WSPdQuery /******************************************************************************* * * WSInfoQuery - CWSStatusThread member function: private operation * (SECONDARY THREAD) * * Query the WinStation information for the WinStation object referenced * by the m_LogonId member variable. * * ENTRY: * * EXIT: * (BOOL) TRUE if query was sucessful; FALSE otherwise. * ******************************************************************************/ BOOL CWSStatusThread::WSInfoQuery() { ULONG ReturnLength; /* * Query the WinStation information. */ TRACE0(">>> CWSStatusThread::WSInfoQuery WinStationQueryInformation\n"); if ( !WinStationQueryInformation( m_hServer, m_LogonId, WinStationInformation, &m_WSInfo, sizeof(WINSTATIONINFORMATION), &ReturnLength ) ) goto BadWSQueryInfo; TRACE0("<<< CWSStatusThread::WSInfoQuery WinStationQueryInformation (success)\n"); return(TRUE); /*-------------------------------------- * Error clean-up and return... */ BadWSQueryInfo: TRACE0("<<< CWSStatusThread::WSInfoQuery WinStationQueryInformation (error)\n"); return(FALSE); } // end CWSStatusThread::WSInfoQuery /////////////////////////////////////////////////////////////////////////////// // CLed class construction / destruction, implementation /******************************************************************************* * * CLed - CLed constructor * * ENTRY: * hBrush (input) * Brush to paint window with. * EXIT: * (Refer to MFC CStatic::CStatic documentation) * ******************************************************************************/ CLed::CLed( HBRUSH hBrush ) : CStatic(), m_hBrush(hBrush) { //{{AFX_DATA_INIT(CLed) //}}AFX_DATA_INIT } // end CLed::CLed //////////////////////////////////////////////////////////////////////////////// // CLed operations /******************************************************************************* * * Subclass - CLed member function: public operation * * Subclass the specified object to our special blip object. * * ENTRY: * pStatic (input) * Points to CStatic object to subclass. * EXIT: * ******************************************************************************/ void CLed::Subclass( CStatic *pStatic ) { SubclassWindow(pStatic->m_hWnd); } // end CLed::Subclass /******************************************************************************* * * Update - CLed member function: public operation * * Update the LED to 'on' or 'off' state. * * ENTRY: * nOn (input) * nonzero to set 'on' state; zero for 'off' state. * EXIT: * ******************************************************************************/ void CLed::Update( int nOn ) { m_bOn = nOn ? TRUE : FALSE; InvalidateRect(NULL); UpdateWindow(); } // end CLed::Update /******************************************************************************* * * Toggle - CLed member function: public operation * * Toggle the LED's on/off state. * * ENTRY: * EXIT: * ******************************************************************************/ void CLed::Toggle() { m_bOn = !m_bOn; InvalidateRect(NULL); UpdateWindow(); } // end CLed::Toggle //////////////////////////////////////////////////////////////////////////////// // CLed message map BEGIN_MESSAGE_MAP(CLed, CStatic) //{{AFX_MSG_MAP(CLed) ON_WM_PAINT() //}}AFX_MSG_MAP END_MESSAGE_MAP() //////////////////////////////////////////////////////////////////////////////// // CLed commands /******************************************************************************* * * OnPaint - CLed member function: public operation * * Paint the led with its brush for 'on' state. * * ENTRY: * EXIT: * (Refer to MFC CWnd::OnPaint documentation) * ******************************************************************************/ void CLed::OnPaint() { RECT rect; CPaintDC dc(this); CBrush brush; GetClientRect(&rect); #ifdef USING_3DCONTROLS (rect.right)--; (rect.bottom)--; dc.FrameRect( &rect, brush.FromHandle((HBRUSH)GetStockObject(GRAY_BRUSH)) ); (rect.top)++; (rect.left)++; (rect.right)++; (rect.bottom)++; dc.FrameRect( &rect, brush.FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)) ); (rect.top)++; (rect.left)++; (rect.right) -= 2; (rect.bottom) -= 2; #else dc.FrameRect( &rect, brush.FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)) ); (rect.top)++; (rect.left)++; (rect.right)--; (rect.bottom)--; #endif dc.FillRect( &rect, brush.FromHandle( m_bOn ? m_hBrush : (HBRUSH)GetStockObject(LTGRAY_BRUSH)) ); } // end CLed::OnPaint ////////////////////////////////////////////////////////////////////////////////