|
|
//Copyright (c) 1998 - 1999 Microsoft Corporation
/*******************************************************************************
* * server.cpp * * implementation of the CServer class * * *******************************************************************************/
#include "stdafx.h"
#include "winadmin.h"
#include "admindoc.h"
#include "dialogs.h"
#include <malloc.h> // for alloca used by Unicode conversion macros
#include <afxconv.h> // for Unicode conversion macros
static int _convert;
#include <winsta.h>
#include <regapi.h>
#include "..\..\inc\utilsub.h"
#include "procs.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
//////////////////////////////////////////////////////////////////////////////////////////
//
// CServer Member Functions
//
//////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CServer::CServer
//
// Constructor for the server class
CServer::CServer(CDomain *pDomain, TCHAR *name, BOOL bFoundLater, BOOL bConnect) { ASSERT(name);
m_ServerFlags = ULONG(0); m_pDomain = pDomain; if(bFoundLater) SetFoundLater(); //m_State = SS_NONE;
m_PreviousState = SS_NONE; m_hTreeItem = NULL; m_hThisServer = NULL; m_hFavTree = NULL; m_pBackgroundThread = NULL; m_bThreadAlive = FALSE; m_pExtensionInfo = NULL; m_pExtServerInfo = NULL; m_pRegistryInfo = NULL; m_fManualFind = FALSE;
// Don't call SetState because we don't want to send a message to the views
m_State = SS_NOT_CONNECTED;
// save off the server name
wcscpy(m_Name, name);
// Dummy up an ExtServerInfo structure
// This is to make it easier for code that tries
// to access this structure before the extension DLL
// has provided it
m_pExtServerInfo = ((CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument())->GetDefaultExtServerInfo();
if(bConnect) Connect();
} // end CServer::CServer
/////////////////////////////////////////////////////////////////////////////
// CServer::~CServer
//
// Destructor for the server class
CServer::~CServer() { // Disconnect();
m_hTreeItem = NULL; m_hFavTree = NULL; m_hThisServer = NULL;
} // end CServer::~CServer
/////////////////////////////////////////////////////////////////////////////
// CServer::RemoveWinStationProcesses
//
// remove all the processes for a given WinStation
void CServer::RemoveWinStationProcesses(CWinStation *pWinStation) { ASSERT(pWinStation);
CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
CObList TempList;
LockProcessList(); POSITION pos = m_ProcessList.GetHeadPosition(); while(pos) { POSITION pos2 = pos; CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos); if(pProcess->GetWinStation() == pWinStation) { // Add the process to our temporary list
TempList.AddTail(pProcess); // Remove the process from the list of processes
pProcess = (CProcess*)m_ProcessList.GetAt(pos2); m_ProcessList.RemoveAt(pos2); } } UnlockProcessList(); pos = TempList.GetHeadPosition(); while(pos) { POSITION pos2 = pos;
CProcess *pProcess = (CProcess*)TempList.GetNext(pos);
// Send a message to remove the Process from the view
CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd(); if(p && ::IsWindow(p->GetSafeHwnd())) { p->SendMessage(WM_ADMIN_REMOVE_PROCESS, 0, (LPARAM)pProcess); } delete pProcess;
}
TempList.RemoveAll();
} // end CServer::RemoveWinStationProcesses
/////////////////////////////////////////////////////////////////////////////
// CServer::ClearAllSelected
//
// Clears the WAF_SELECTED bit in all of this server's lists
//
void CServer::ClearAllSelected() { // Clear the WinStation list WAF_SELECTED flags
// Iterate through the WinStation list
LockWinStationList( );
POSITION pos = m_WinStationList.GetHeadPosition();
while(pos) { CWinStation *pWinStation = (CWinStation*)m_WinStationList.GetNext(pos); pWinStation->ClearSelected(); }
m_NumWinStationsSelected = 0;
UnlockWinStationList( );
LockProcessList(); // Clear the Process list PF_SELECTED flags
// Iterate through the Process list
pos = m_ProcessList.GetHeadPosition(); while(pos) { CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos); pProcess->ClearSelected(); }
m_NumProcessesSelected = 0;
UnlockProcessList( );
} // end CServer::ClearAllSelected
//Function - htol - start
//===========================================================================
//
//Description: converts a hex string to a uLONG, handles "0x..."
//
//
//Parameters:
//
//Return Value:
//
//Global Variables Affected:
//
//Remarks: (Side effects, Assumptions, Warnings...)
//
//
//---------------------------------------------------------------------------
WCHAR hextable[] = L"0123456789ABCDEF";
ULONG htol(WCHAR *hexString) { ULONG retValue = 0L;
// convert the string to upper case
_wcsupr(hexString);
WCHAR *p = hexString;
while (*p == L' ') p++;
while(*p) { if(*p == L'X') { retValue = 0L; } else if ((*p == L' ') || (*p == L'\n') || (*p == L'\r')) break; else if(*p == L'.') { // skip over a decimal point
} else { retValue <<= 4; for(int i = 0; i < 16; i++) { if(hextable[i] == *p) { retValue += i; break; } } } *p++; }
return retValue; }
static TCHAR szMicrosoftKey[] = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"); static TCHAR szInstallDate[] = TEXT("InstallDate"); static TCHAR szCSDVersion[] = TEXT("CSDVersion"); static TCHAR szCurrentVersion[] = TEXT("CurrentVersion"); static TCHAR szCurrentBuildNumber[] = TEXT("CurrentBuildNumber"); static TCHAR szCurrentProductName[] = TEXT("ProductName"); static TCHAR szHotfixKey[] = TEXT("HOTFIX"); static TCHAR szValid[] = TEXT("Valid"); static TCHAR szInstalledOn[] = TEXT("Installed On"); static TCHAR szInstalledBy[] = TEXT("Installed By"); #define REG_CONTROL_CITRIX REG_CONTROL L"\\Citrix"
/////////////////////////////////////////////////////////////////////////////
// CServer::BuildRegistryInfo
//
// Go out and fill in the registry info structure
BOOL CServer::BuildRegistryInfo() { DWORD dwType, dwSize; HKEY hKeyServer; HKEY hKey;
if(!IsServerSane()) return FALSE;
m_pRegistryInfo = new ServerRegistryInfo; if(!m_pRegistryInfo) return FALSE; memset(m_pRegistryInfo, 0, sizeof(ServerRegistryInfo));
TCHAR Buffer[128]; Buffer[0] = TEXT('\\'); Buffer[1] = TEXT('\\'); Buffer[2] = TEXT('\0'); wcscpy(Buffer+2, m_Name);
/*
* Connect to the server's registry * (avoid using RPC when the server is the local machine.) */
if(RegConnectRegistry(IsCurrentServer() ? NULL : Buffer, HKEY_LOCAL_MACHINE, &hKeyServer) != ERROR_SUCCESS) return FALSE;
/*
* Fetch MS information. */ if(RegOpenKeyEx(hKeyServer, szMicrosoftKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { RegCloseKey(hKeyServer); return FALSE; }
dwSize = sizeof(m_pRegistryInfo->InstallDate); if(RegQueryValueEx(hKey, szInstallDate, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->InstallDate, &dwSize) != ERROR_SUCCESS) { m_pRegistryInfo->InstallDate = 0xFFFFFFFF; }
// REMARK: we should check the returned codes for every RegQueryValueEx
dwSize = sizeof(m_pRegistryInfo->ServicePackLevel); RegQueryValueEx(hKey, szCSDVersion, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->ServicePackLevel, &dwSize); dwSize = sizeof(m_pRegistryInfo->MSVersion); RegQueryValueEx(hKey, szCurrentVersion, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->MSVersion, &dwSize); m_pRegistryInfo->MSVersionNum = _wtol(m_pRegistryInfo->MSVersion);
dwSize = sizeof(m_pRegistryInfo->MSBuild); RegQueryValueEx(hKey, szCurrentBuildNumber, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->MSBuild, &dwSize); dwSize = sizeof(m_pRegistryInfo->MSProductName); RegQueryValueEx(hKey, szCurrentProductName, NULL, &dwType, (LPBYTE)&m_pRegistryInfo->MSProductName, &dwSize); HKEY hKeyHotfix;
if(RegOpenKeyEx(hKey, szHotfixKey, 0, KEY_READ, &hKeyHotfix) == ERROR_SUCCESS) { DWORD Index = 0; FILETIME LastWriteTime; dwSize = sizeof(Buffer) / sizeof( TCHAR ); while(RegEnumKeyEx(hKeyHotfix, Index, Buffer, &dwSize, NULL, NULL, NULL, &LastWriteTime) == ERROR_SUCCESS) { HKEY hKeySingleHotfix; if(RegOpenKeyEx(hKeyHotfix, Buffer, 0, KEY_READ, &hKeySingleHotfix) == ERROR_SUCCESS) { // Create a CHotFix object
CHotfix *pHotfix = new CHotfix;
if(pHotfix) { // Copy the Hotfix name
// Get rid of the WF: if it's there
if(wcsncmp(Buffer, TEXT("WF:"), 3) == 0) { wcscpy(pHotfix->m_Name, &Buffer[3]); } else wcscpy(pHotfix->m_Name, Buffer);
// Get the Valid entry
dwSize = sizeof(&pHotfix->m_Valid); if(RegQueryValueEx(hKeySingleHotfix, szValid, NULL, &dwType, (LPBYTE)&pHotfix->m_Valid, &dwSize) != ERROR_SUCCESS) { pHotfix->m_Valid = 0L; }
// Get the Installed On entry
dwSize = sizeof(&pHotfix->m_InstalledOn); if(RegQueryValueEx(hKeySingleHotfix, szInstalledOn, NULL, &dwType, (LPBYTE)&pHotfix->m_InstalledOn, &dwSize) != ERROR_SUCCESS) { pHotfix->m_InstalledOn = 0xFFFFFFFF; }
// Get the Installed By entry
dwSize = sizeof(pHotfix->m_InstalledBy); if(RegQueryValueEx(hKeySingleHotfix, szInstalledBy, NULL, &dwType, (LPBYTE)pHotfix->m_InstalledBy, &dwSize) != ERROR_SUCCESS) { pHotfix->m_InstalledBy[0] = '\0'; }
pHotfix->m_pServer = this;
m_HotfixList.AddTail(pHotfix);
RegCloseKey(hKeySingleHotfix); } }
dwSize = sizeof(Buffer) / sizeof( TCHAR ); Index++; }
RegCloseKey(hKeyHotfix); }
RegCloseKey(hKey);
if (m_pRegistryInfo->MSVersionNum < 5) // only for TS 4.0
{ /*
* Fetch Citrix information. */ // Look in the new location
LONG result = RegOpenKeyEx(hKeyServer, REG_CONTROL_TSERVER, 0, KEY_READ, &hKey);
if(result != ERROR_SUCCESS) { // Look in the old location
result = RegOpenKeyEx(hKeyServer, REG_CONTROL_CITRIX, 0, KEY_READ, &hKey); }
if(result != ERROR_SUCCESS) { RegCloseKey(hKeyServer); return FALSE; }
dwSize = sizeof(m_pRegistryInfo->CTXProductName); RegQueryValueEx(hKey, REG_CITRIX_PRODUCTNAME, NULL, &dwType, (LPBYTE)m_pRegistryInfo->CTXProductName, &dwSize); dwSize = sizeof(m_pRegistryInfo->CTXVersion); RegQueryValueEx(hKey, REG_CITRIX_PRODUCTVERSION, NULL, &dwType, (LPBYTE)m_pRegistryInfo->CTXVersion, &dwSize);
m_pRegistryInfo->CTXVersionNum = htol(m_pRegistryInfo->CTXVersion);
dwSize = sizeof(m_pRegistryInfo->CTXBuild); RegQueryValueEx(hKey, REG_CITRIX_PRODUCTBUILD, NULL, &dwType, (LPBYTE)m_pRegistryInfo->CTXBuild, &dwSize);
RegCloseKey(hKey);
} else // for NT 5.0 and beyond, do not query the registry
{ //REMARK: we should get rid of all this.
wcscpy(m_pRegistryInfo->CTXProductName, m_pRegistryInfo->MSProductName); wcscpy(m_pRegistryInfo->CTXVersion, m_pRegistryInfo->MSVersion); m_pRegistryInfo->CTXVersionNum = m_pRegistryInfo->MSVersionNum; wcscpy(m_pRegistryInfo->CTXBuild, m_pRegistryInfo->MSBuild); }
RegCloseKey(hKeyServer);
// Set the flag to say the info is valid
SetRegistryInfoValid();
return TRUE;
} // end CServer::BuildRegistryInfo
/////////////////////////////////////////////////////////////////////////////
// CServer::AddWinStation
//
// Add a WinStation to the Server's WinStationList in
// sorted order
// NOTE: The list should be NOT be locked by the caller
//
void CServer::AddWinStation(CWinStation *pNewWinStation) { ASSERT(pNewWinStation);
LockWinStationList();
ODS( L"CServer!AddWinStation\n" );
BOOLEAN bAdded = FALSE; POSITION pos, oldpos; int Index;
// Traverse the WinStationList and insert this new WinStation,
// keeping the list sorted by Sort Order, then Protocol.
for(Index = 0, pos = m_WinStationList.GetHeadPosition(); pos != NULL; Index++) { oldpos = pos; CWinStation *pWinStation = (CWinStation*)m_WinStationList.GetNext(pos);
if((pWinStation->GetSortOrder() > pNewWinStation->GetSortOrder()) || ((pWinStation->GetSortOrder() == pNewWinStation->GetSortOrder()) && (pWinStation->GetSdClass() > pNewWinStation->GetSdClass()))) { // The new object belongs before the current list object.
m_WinStationList.InsertBefore(oldpos, pNewWinStation); bAdded = TRUE; break; } }
// If we haven't yet added the WinStation, add it now to the tail
// of the list.
if(!bAdded) { m_WinStationList.AddTail(pNewWinStation); }
UnlockWinStationList();
} // end CServer::AddWinStation
/////////////////////////////////////////////////////////////////////////////
// CServer::Connect
//
// Connect to the server
//
BOOL CServer::Connect() { m_NumProcessesSelected = 0; m_NumWinStationsSelected = 0; m_pExtServerInfo = NULL; BOOL bResult = FALSE; if(m_State != SS_NOT_CONNECTED ) { return FALSE; } // Fire off the background thread for this server
LockThreadAlive(); if(m_pBackgroundThread == NULL) { ServerProcInfo *pProcInfo = new ServerProcInfo; if(pProcInfo) { pProcInfo->pServer = this; pProcInfo->pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument(); m_BackgroundContinue = TRUE; m_bThreadAlive = FALSE; m_pBackgroundThread = AfxBeginThread((AFX_THREADPROC)CServer::BackgroundThreadProc, pProcInfo, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL ); if( m_pBackgroundThread == NULL ) { ODS( L"CServer!Connect possibly low resources no thread created\n" ); delete pProcInfo; return FALSE; } m_pBackgroundThread->m_bAutoDelete = FALSE; if (m_pBackgroundThread->ResumeThread() <= 1) { bResult = TRUE; } } } UnlockThreadAlive(); return TRUE; }
/////////////////////////////////////////////////////////////////////////////
// CServer::Disconnect
//
// Disconnect from the server
//
void CServer::Disconnect() { // not a good idea for an ods
CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
SetState(SS_DISCONNECTING);
// If there is an extension DLL, let it cleanup anything it added to this Server
LPFNEXSERVERCLEANUPPROC CleanupProc = ((CWinAdminApp*)AfxGetApp())->GetExtServerCleanupProc(); if(CleanupProc && m_pExtensionInfo) { (*CleanupProc)(m_pExtensionInfo); m_pExtensionInfo = NULL; }
// Tell the background thread to terminate and
// wait for it to do so.
LockThreadAlive();
ClearBackgroundContinue();
if( !m_pBackgroundThread ) { // Either there is no background thread at all,
// or some other thread is taking care of terminating it.
// Just do nothing.
//ODS( L"TSADMIN:CServer::Disconnect UnlockThreadAlive\n" );
UnlockThreadAlive(); } else { if( m_bThreadAlive ) { // the thread is alive. Tell him to exit.
// keep temporary pointer and handle
CWinThread *pBackgroundThread = m_pBackgroundThread;
HANDLE hThread = m_pBackgroundThread->m_hThread;
// Clear the pointer before releasing the lock
m_pBackgroundThread = NULL;
// Give the thread a chance to exit
UnlockThreadAlive();
// Force him out of waiting for an event if he is
ULONG WSEventFlags;
if(IsHandleGood()) { ODS( L"TSADMIN:CServer::Disconnect Handle is good flush events\n" );
WinStationWaitSystemEvent(m_Handle, WEVENT_FLUSH, &WSEventFlags); }
if( hThread ) // It should always be TRUE
{ // If this server object is waiting for RPC to timeout,
// just kill the thread
if( m_PreviousState == SS_NOT_CONNECTED ) { ODS( L"TSADMIN:CServer::Disconnect Previous state not connected termthread\n" );
if( WaitForSingleObject( hThread , 100 ) == WAIT_TIMEOUT ) { TerminateThread(hThread, 0); } } // For all other threads, wait a second and then kill it
else if( WaitForSingleObject( hThread , 1000 ) == WAIT_TIMEOUT ) { ODS( L"TSADMIN CServer!Disconnect prevstate was !not_connected termthread\n" );
TerminateThread(hThread, 0); }
WaitForSingleObject(hThread, INFINITE); } else { ASSERT(FALSE); }
// delete the CWinThread object
ODS( L"TSADMIN:CServer::Disconnect delete CWinThread Object m_bThread == TRUE\n" ); delete pBackgroundThread; } else { // the thread is dead or will be dead very soon. Just do the cleanup.
ODS( L"TSADMIN:CServer::Disconnect delete CWinThread Object m_bThread == FALSE\n" ); delete m_pBackgroundThread; m_pBackgroundThread = NULL; UnlockThreadAlive();
} }
if(IsHandleGood()) { ODS( L"TSADMIN:CServer::Disconnect WinStationCloseServer\n" ); WinStationCloseServer(m_Handle); m_Handle = NULL; }
LockWinStationList();
CObList TempList;
// Iterate through the WinStation list
// Move all the WinStations to a temporary list so that
// we don't have to have the WinStationList locked while
// sending the WM_ADMIN_REMOVE_WINSTATION message to the views.
POSITION pos = m_WinStationList.GetHeadPosition();
while(pos) { CWinStation *pWinStation = (CWinStation*)m_WinStationList.GetNext(pos); TempList.AddTail(pWinStation); }
m_WinStationList.RemoveAll();
UnlockWinStationList(); CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd();
pos = TempList.GetHeadPosition();
while(pos) { CWinStation *pWinStation = (CWinStation*)TempList.GetNext(pos);
if(p && ::IsWindow(p->GetSafeHwnd())) { ODS( L"TSADMIN:CServer::Disconnect Remove WinStation\n" ); p->SendMessage(WM_ADMIN_REMOVE_WINSTATION, 0, (LPARAM)pWinStation); }
delete pWinStation; }
TempList.RemoveAll();
LockProcessList();
pos = m_ProcessList.GetHeadPosition();
while(pos) { CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos);
ODS( L"TSADMIN:CServer::Disconnect Delete process\n" );
delete pProcess; }
m_ProcessList.RemoveAll(); UnlockProcessList();
LockLicenseList(); pos = m_LicenseList.GetHeadPosition();
while(pos) { CLicense *pLicense = (CLicense*)m_LicenseList.GetNext(pos);
ODS( L"TSADMIN:CServer::Disconnect remove license\n" );
delete pLicense; }
m_LicenseList.RemoveAll(); UnlockLicenseList();
//
pos = m_UserSidList.GetHeadPosition();
while(pos) { CUserSid *pUserSid = (CUserSid*)m_UserSidList.GetNext(pos);
ODS( L"TSADMIN:CServer::Disconnect remove sids\n" );
delete pUserSid; }
m_UserSidList.RemoveAll();
pos = m_HotfixList.GetHeadPosition();
while(pos) { CHotfix *pHotfix = (CHotfix*)m_HotfixList.GetNext(pos);
ODS( L"TSADMIN:CServer::Disconnect Remove hotfixes\n" );
delete pHotfix; }
m_HotfixList.RemoveAll();
if( m_pRegistryInfo ) { delete m_pRegistryInfo;
ODS( L"TSADMIN:CServer::Disconnect delete reginfo\n" );
m_pRegistryInfo = NULL; } // ODS( L"TSADMIN:CServer::Disconnect Set state not connected\n" );
SetState(SS_NOT_CONNECTED); }
/////////////////////////////////////////////////////////////////////////////
// CServer::DoDetail
//
// Go get detailed information about this server
//
void CServer::DoDetail() { CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
SetState(SS_GETTING_INFO);
ULONG Entries; PLOGONID pLogonId;
if(!ShouldBackgroundContinue()) return;
// We need to access the registry information for the server
// at this time because we must not administer WF 2.00 servers
// (RPC structures are incompatible). If we cannot access the
// server's registry, or the multi-user version is 2.00, we bail
// from this server.
if ( !BuildRegistryInfo() || (GetCTXVersionNum() == 0x200) || (GetCTXVersionNum() == 0) ) { ClearHandleGood(); SetLostConnection(); SetState(SS_BAD);
ODS( L"CServer::DoDetail - Setting to lost connection\n" );
CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd(); if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) pFrameWnd->SendMessage(WM_ADMIN_REMOVE_SERVER, 0, (LPARAM)this); ClearBackgroundContinue(); return; }
// Find all the WinStations
BOOL fWinEnum;
fWinEnum = WinStationEnumerate(m_Handle, &pLogonId, &Entries);
DBGMSG( L"CServer!DoDetail WinEnum last reported error 0x%x\n", GetLastError( ) );
if(!fWinEnum ) { ClearHandleGood(); SetLostConnection(); SetState(SS_BAD); ClearBackgroundContinue(); return; }
if(!ShouldBackgroundContinue()) { if(pLogonId) WinStationFreeMemory(pLogonId); return; }
// Get information about the WinStations
if(pLogonId) { for(ULONG i = 0; i < Entries; i++) { // Create a new WinStation object
CWinStation *pWinStation = new CWinStation(this, &pLogonId[i]); if(pWinStation) { // If the queries weren't successful, ignore this WinStation
if(!pWinStation->QueriesSuccessful()) { ODS( L"CServer::DoDetail!QueriesSuccessful failed\n" ); delete pWinStation; } else { AddWinStation(pWinStation); pWinStation->SetNew(); } }
if( !ShouldBackgroundContinue() ) { if(pLogonId) WinStationFreeMemory(pLogonId); return; } }
WinStationFreeMemory(pLogonId); }
if(!ShouldBackgroundContinue()) return;
// If there is an extension DLL loaded, allow it to add it's own info for this Server
LPFNEXSERVERINITPROC InitProc = ((CWinAdminApp*)AfxGetApp())->GetExtServerInitProc(); if(InitProc) { m_pExtensionInfo = (*InitProc)(m_Name, m_Handle); if(m_pExtensionInfo) { LPFNEXGETSERVERINFOPROC GetInfoProc = ((CWinAdminApp*)AfxGetApp())->GetExtGetServerInfoProc(); if(GetInfoProc) { m_pExtServerInfo = (*GetInfoProc)(m_pExtensionInfo); // If this server is running WinFrame or Picasso, set flag
if(m_pExtServerInfo->Flags & ESF_WINFRAME) SetWinFrame(); } } }
QueryLicenses();
SetState(SS_GOOD);
// Send a message to the views to tell it the state of this
// server has changed
CFrameWnd *p = (CFrameWnd*)pDoc->GetMainWnd(); if(p && ::IsWindow(p->GetSafeHwnd())) { p->SendMessage(WM_ADMIN_UPDATE_SERVER_INFO, 0, (LPARAM)this); p->SendMessage(WM_ADMIN_UPDATE_WINSTATIONS, 0, (LPARAM)this); }
} // end CServer::DoDetail
/////////////////////////////////////////////////////////////////////////////
// CServer::FindProcessByPID
//
// returns a pointer to a CProcess from m_ProcessList given a PID
CProcess* CServer::FindProcessByPID(ULONG Pid) { LockProcessList(); POSITION pos = m_ProcessList.GetHeadPosition(); while(pos) { CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos); if(pProcess->GetPID() == Pid) { UnlockProcessList(); return pProcess; } }
UnlockProcessList();
return NULL;
} // end CServer::FindProcessByPID
/////////////////////////////////////////////////////////////////////////////
// CServer::EnumerateProcesses
//
// Enumerate this server's processes
BOOL CServer::EnumerateProcesses() { ENUMTOKEN EnumToken; ULONG PID; ULONG LogonId; TCHAR ImageName[MAX_PROCESSNAME+1]; PSID pSID; EnumToken.Current = 0; EnumToken.NumberOfProcesses = 0; EnumToken.ProcessArray = NULL; EnumToken.bGAP = TRUE;
if(!IsHandleGood()) return 0;
CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument(); LockProcessList();
// Loop processes through and turn off current flag and new flag
// Delete any processes that aren't current
POSITION pos = m_ProcessList.GetHeadPosition(); while(pos) { POSITION pos2 = pos; CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos); if(!pProcess->IsCurrent()) { pProcess = (CProcess*)m_ProcessList.GetAt(pos2); m_ProcessList.RemoveAt(pos2); delete pProcess; } else { pProcess->ClearCurrent(); pProcess->ClearNew(); pProcess->ClearChanged(); // !
} }
UnlockProcessList();
// Should we quit?
if(!pDoc->ShouldProcessContinue()) { return FALSE; }
while(ProcEnumerateProcesses(m_Handle, &EnumToken, ImageName, &LogonId, &PID, &pSID )) {
CProcess *pProcess = new CProcess(PID, LogonId, this, pSID, FindWinStationById(LogonId), ImageName); if(pProcess) { // If this process is in the list, we need to see if it has changed
CProcess *pOldProcess = FindProcessByPID(PID); if(pOldProcess && pProcess->GetWinStation()) { // Flag the process as current
pOldProcess->SetCurrent(); // Update any info that has changed
pOldProcess->Update(pProcess); // We don't need this process object anymore
delete pProcess; } // It is a new process, add it to the list
else if(pProcess->GetWinStation()) { pProcess->SetNew(); LockProcessList(); m_ProcessList.AddTail(pProcess); UnlockProcessList(); } // This process doesn't have a WinStation, delete it
else { delete pProcess; } }
// Should we quit?
if(!pDoc->ShouldProcessContinue()) { // We have to call this one last time with an offset of -1 to
// make the function free up the memory allocated by the client side stub.
EnumToken.Current = (ULONG)-1; ProcEnumerateProcesses(m_Handle, &EnumToken, ImageName, &LogonId, &PID, &pSID );
return FALSE; } }
return TRUE;
} // end CServer::EnumerateProcesses
/////////////////////////////////////////////////////////////////////////////
// CServer::ClearProcesses
//
// Clear out the list of processes
void CServer::ClearProcesses() { LockProcessList(); POSITION pos = m_ProcessList.GetHeadPosition();
while(pos) { CProcess *pProcess = (CProcess*)m_ProcessList.GetNext(pos); delete pProcess; }
m_ProcessList.RemoveAll(); UnlockProcessList();
} // end CServer::ClearProcesses
/////////////////////////////////////////////////////////////////////////////
// CServer::FindWinStationById
//
CWinStation* CServer::FindWinStationById(ULONG Id) { LockWinStationList(); POSITION pos = m_WinStationList.GetHeadPosition(); while(pos) { CWinStation *pWinStation = (CWinStation*)m_WinStationList.GetNext(pos); if(pWinStation->GetLogonId() == Id) { UnlockWinStationList(); return pWinStation; } }
UnlockWinStationList();
return NULL;
} // end CServer::FindWinStationById
/////////////////////////////////////////////////////////////////////////////
// CServer::BackgroundThreadProc
//
UINT CServer::BackgroundThreadProc(LPVOID pParam) { ASSERT(pParam); ODS( L"CServer::BackgroundThreadProc\n" );
// We need a pointer to the document so we can make
// calls to member functions
CWinAdminDoc *pDoc = (CWinAdminDoc*)((ServerProcInfo*)pParam)->pDoc; CServer *pServer = ((ServerProcInfo*)pParam)->pServer;
HANDLE hServer;
delete (ServerProcInfo*)pParam;
// Make sure we don't have to quit
if(!pServer->ShouldBackgroundContinue()) { return 0; }
pServer->SetThreadAlive();
// In case the server is disconnected we wait uselessly here
while(!pDoc->AreAllViewsReady()) Sleep(500);
// Make sure we don't have to quit
if(!pServer->ShouldBackgroundContinue()) { pServer->ClearThreadAlive(); return 0; }
if(!pServer->IsCurrentServer()) { // open the server and save the handle
hServer = WinStationOpenServer(pServer->GetName()); pServer->SetHandle(hServer); // Make sure we don't have to quit
if(!pServer->ShouldBackgroundContinue()) { pServer->ClearThreadAlive();
return 0; } if(hServer == NULL) { DWORD Error = GetLastError();
DBGMSG( L"CServer!BackgroundThreadProc WinStationOpenServer failed with 0x%x\n", Error );
if(Error == RPC_S_SERVER_UNAVAILABLE) { pServer->ClearBackgroundFound();
pServer->SetLostConnection();
pServer->ClearManualFind( ); CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) { ODS( L"Server backgrnd thread declares this server RPC_S_SERVER_UNAVAILABLE\n" ); pFrameWnd->SendMessage(WM_ADMIN_REMOVE_SERVER, 0, (LPARAM)pServer);
if( pServer->GetTreeItemFromFav() != NULL ) { pFrameWnd->SendMessage( WM_ADMIN_REMOVESERVERFROMFAV , 0 , ( LPARAM )pServer ); } } } else { pServer->SetState(SS_BAD); }
pServer->ClearThreadAlive();
return 0; }
pServer->SetHandleGood(); pServer->SetState(SS_OPENED); } else { hServer = SERVERNAME_CURRENT; pServer->SetHandle(SERVERNAME_CURRENT); pServer->SetHandleGood(); pServer->SetState(SS_OPENED); }
// Make sure we don't have to quit
if(!pServer->ShouldBackgroundContinue()) { pServer->ClearThreadAlive(); return 0; }
// If we found this server after initial enum,
// we need to add it to the views now
CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
if(pServer->WasFoundLater()) { if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) { pFrameWnd->SendMessage(WM_ADMIN_ADD_SERVER, ( WPARAM )TVI_SORT, (LPARAM)pServer); } } // Make sure we don't have to quit
if(!pServer->ShouldBackgroundContinue()) { pServer->ClearThreadAlive(); return 0; } pServer->DoDetail(); // Now go into our loop waiting for WinStation Events
while(1) { ULONG WSEventFlags; ULONG Entries; PLOGONID pLogonId;
// Make sure we don't have to quit
if(!pServer->ShouldBackgroundContinue()) { pServer->ClearThreadAlive(); return 0; }
// Wait for the browser to tell us something happened
if(!WinStationWaitSystemEvent(hServer, WEVENT_ALL, &WSEventFlags)) { if(GetLastError() != ERROR_OPERATION_ABORTED) { ODS( L"CServer::BackgroundThreadProc ERROR_OPERATION_ABORTED\n" ); pServer->ClearHandleGood(); pServer->SetState(SS_BAD); pServer->SetLostConnection(); pServer->ClearThreadAlive(); pServer->ClearManualFind( ); return 1; } }
ODS( L"CServer::BackgroundThreadProc -- some system event has taken place\n" );
// Make sure we don't have to quit
if(!pServer->ShouldBackgroundContinue()) { pServer->ClearThreadAlive(); ODS( L"CServer::BackgroundThreadProc -* backgrnd thread should not continue\n" ); return 0; }
// Loop through this Server's WinStations and clear the current flag
pServer->LockWinStationList(); CObList *pWinStationList = pServer->GetWinStationList(); POSITION pos = pWinStationList->GetHeadPosition(); while(pos) { CWinStation *pWinStation = (CWinStation*)pWinStationList->GetNext(pos); pWinStation->ClearCurrent(); pWinStation->ClearNew(); pWinStation->ClearChanged(); } pServer->UnlockWinStationList();
// Find all the WinStations
BOOL fWinEnum = WinStationEnumerate(hServer, &pLogonId, &Entries);
DBGMSG( L"CServer!BackgroundThread WinEnum last reported error 0x%x\n", GetLastError( ) );
if(!fWinEnum ) { ODS( L"CServer!BackgroundThread -- server is no longer valid\n" );
pServer->ClearHandleGood();
pServer->SetLostConnection(); pServer->SetState(SS_BAD); pServer->ClearThreadAlive(); pServer->ClearManualFind( ); return 1; } // Make sure we don't have to quit
if(!pServer->ShouldBackgroundContinue()) { if(pLogonId) WinStationFreeMemory(pLogonId); pServer->ClearThreadAlive(); ODS( L"CServer!BackgroundThreadProc -# backgrnd thread should not continue\n" ); return 0; }
if(pLogonId) { // Get information about the WinStations
for(ULONG i = 0; i < Entries; i++) { // Look for this WinStation in the list
CWinStation *pWinStation = pServer->FindWinStationById(pLogonId[i].LogonId); if(pWinStation) { // Mark this WinStation as current
pWinStation->SetCurrent();
// We found the WinStation in the list
// Create a new CWinStation object - he will get his information
CWinStation *pTempWinStation = new CWinStation(pServer, &pLogonId[i]);
if(pTempWinStation) { // If any information has changed, send a message to update the views
if(pWinStation->Update(pTempWinStation)) { CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) { pFrameWnd->SendMessage(WM_ADMIN_UPDATE_WINSTATION, 0, (LPARAM)pWinStation); }
}
// We don't need the temporary CWinStation object anymore
delete pTempWinStation; } } else { // We didn't find it in our list
// We don't want to add it to our list if the WinStation is down
if(pLogonId[i].State != State_Down && pLogonId[i].State != State_Init) { // Create a new CWinStation object
CWinStation *pNewWinStation = new CWinStation(pServer, &pLogonId[i]); if(pNewWinStation) { pServer->AddWinStation(pNewWinStation); pNewWinStation->SetNew(); CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) { pFrameWnd->SendMessage(WM_ADMIN_ADD_WINSTATION, 0, (LPARAM)pNewWinStation); }
} } } }
WinStationFreeMemory(pLogonId);
// Send a message to the views to update their WinStations
CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) { pFrameWnd->SendMessage(WM_ADMIN_UPDATE_WINSTATIONS, 0, (LPARAM)pServer); }
// Loop through the WinStations for this server and move
// any that aren't current to a temporary list
CObList TempList;
pServer->LockWinStationList(); CObList *pWinStationList = pServer->GetWinStationList(); POSITION pos = pWinStationList->GetHeadPosition(); while(pos) { POSITION pos2 = pos; CWinStation *pWinStation = (CWinStation*)pWinStationList->GetNext(pos); if(!pWinStation->IsCurrent()) { // Add the WinStation to our temporary list
TempList.AddTail(pWinStation); // Remove the WinStation from the list of WinStations
pWinStation = (CWinStation*)pWinStationList->GetAt(pos2); pWinStationList->RemoveAt(pos2); } } pServer->UnlockWinStationList();
pos = TempList.GetHeadPosition(); while(pos) { POSITION pos2 = pos;
CWinStation *pWinStation = (CWinStation*)TempList.GetNext(pos);
// Send a message to remove the WinStation from the tree view
CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) { pFrameWnd->SendMessage(WM_ADMIN_REMOVE_WINSTATION, 0, (LPARAM)pWinStation); } delete pWinStation; }
TempList.RemoveAll();
} // end if(pLogonId)
// If there is an extension DLL loaded, allow it to update info for this Server
LPFNEXSERVEREVENTPROC EventProc = ((CWinAdminApp*)AfxGetApp())->GetExtServerEventProc(); if(EventProc) { // Returns TRUE if anything changed
if((*EventProc)(pServer->GetExtensionInfo(), WSEventFlags)) { pServer->QueryLicenses();
CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) { pFrameWnd->SendMessage(WM_ADMIN_REDISPLAY_LICENSES, 0, (LPARAM)pServer); }
} }
// Tell the Server view to show the new load and license counts
CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd();
if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) { pFrameWnd->SendMessage(WM_ADMIN_UPDATE_SERVER_INFO, 0, (LPARAM)pServer); }
// Make sure we don't have to quit
if(!pServer->ShouldBackgroundContinue()) { pServer->ClearThreadAlive(); ODS( L"CServer::BackgroundThreadProc -@ backgrnd thread should not continue\n" ); return 0; }
} // end while(1)
} // end CServer::BackgroundThreadProc
/////////////////////////////////////////////////////////////////////////////
// CServer::QueryLicenses
//
void CServer::QueryLicenses() { ULONG NumLicenses; ExtLicenseInfo *pExtLicenseInfo = NULL;
// If there is an extension DLL loaded, get this server's list of licenses
LPFNEXGETSERVERLICENSESPROC LicenseProc = ((CWinAdminApp*)AfxGetApp())->GetExtGetServerLicensesProc(); if(LicenseProc && m_pExtensionInfo) {
LockLicenseList();
// Iterate through the License list
POSITION pos = m_LicenseList.GetHeadPosition();
while(pos) { CLicense *pLicense = (CLicense*)m_LicenseList.GetNext(pos); delete pLicense; } m_LicenseList.RemoveAll();
UnlockLicenseList();
pExtLicenseInfo = (*LicenseProc)(m_pExtensionInfo, &NumLicenses); if(pExtLicenseInfo) { ExtLicenseInfo *pExtLicense = pExtLicenseInfo;
for(ULONG lic = 0; lic < NumLicenses; lic++) { CLicense *pLicense = new CLicense(this, pExtLicense); if(pLicense) { AddLicense(pLicense); } pExtLicense++; } // Get the extension DLL's function to free the license info
LPFNEXFREESERVERLICENSESPROC LicenseFreeProc = ((CWinAdminApp*)AfxGetApp())->GetExtFreeServerLicensesProc(); if(LicenseFreeProc) { (*LicenseFreeProc)(pExtLicenseInfo); } else { TRACE0("WAExGetServerLicenses exists without WAExFreeServerLicenseInfo\n"); ASSERT(0); } } }
} // end CServer::QueryLicenses
/////////////////////////////////////////////////////////////////////////////
// CServer::AddLicense
//
// Add a License to the Server's LicenseList in
// sorted order
// NOTE: The list should be NOT be locked by the caller
//
void CServer::AddLicense(CLicense *pNewLicense) { ASSERT(pNewLicense);
LockLicenseList();
BOOLEAN bAdded = FALSE; POSITION pos, oldpos; int Index;
// Traverse the LicenseList and insert this new License,
// keeping the list sorted by Class, then Name.
for(Index = 0, pos = m_LicenseList.GetHeadPosition(); pos != NULL; Index++) { oldpos = pos; CLicense *pLicense = (CLicense*)m_LicenseList.GetNext(pos);
if((pLicense->GetClass() > pNewLicense->GetClass()) || ((pLicense->GetClass() == pNewLicense->GetClass()) && lstrcmpi(pLicense->GetSerialNumber(), pNewLicense->GetSerialNumber()) > 0)) {
// The new object belongs before the current list object.
m_LicenseList.InsertBefore(oldpos, pNewLicense); bAdded = TRUE; break; } }
// If we haven't yet added the License, add it now to the tail
// of the list.
if(!bAdded) { m_LicenseList.AddTail(pNewLicense); }
UnlockLicenseList();
} // end CServer::AddLicense
/////////////////////////////////////////////////////////////////////////////
// CServer::SetState
//
void CServer::SetState(SERVER_STATE State) { m_PreviousState = m_State;
m_State = State;
if(m_State != m_PreviousState) { CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
CFrameWnd *pFrameWnd = (CFrameWnd*)pDoc->GetMainWnd(); if(pFrameWnd && ::IsWindow(pFrameWnd->GetSafeHwnd())) { pFrameWnd->SendMessage(WM_ADMIN_UPDATE_SERVER, 0, (LPARAM)this); } }
} // end CServer::SetState
|