// MachineView.cpp : implementation of the CMachineView class
//
#include "stdafx.h"
#include "RemoteAdmin.h"
#include "GlobalMFCHelperFunc.h"
#include "GlobalHelperFunc.h"
#include "RemoteAdminDoc.h"
#include "MachineView.h"
#include "MainFrame.h"
#include "RemoteLogonDlg.h"
#include "MachineInfo.h"
#include "RemoteAdminView.h"
#include "RemoteProcessDlg.h"
#include "ProgressWndThread.h"
#include "Command.h"
#include "ConnectionThread.h"
#include <process.h>
#include <Tlhelp32.h>
#include <windows.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMachineView
IMPLEMENT_DYNCREATE(CMachineView, CTreeView)
BEGIN_MESSAGE_MAP(CMachineView, CTreeView)
//{{AFX_MSG_MAP(CMachineView)
ON_WM_RBUTTONDOWN()
ON_COMMAND(ID_MACHINEPROPERTIES_REFRESHPROCESS, OnRefreshProcess)
ON_WM_LBUTTONDOWN()
ON_COMMAND(ID_MACHINEPROPERTIES_EXECUTE_PROCESS, OnExecuteProcess)
ON_COMMAND(ID_MACHINEPROPERTIES_SHUTDOWN_HALT, OnShutdownHalt)
ON_COMMAND(ID_MACHINEOPTIONS_ADD_MACHINE, OnAddMachine)
ON_COMMAND(ID_MACHINEOPTIONS_DELETE_MACHINE, OnDeleteMachine)
ON_COMMAND(ID_MACHINEPROPERTIES_DELETE_MACHINE, OnDeleteMachine)
ON_COMMAND(ID_MACHINEPROPERTIES_SHUTDOWN_ABORTSHUTDOWN, OnShutdownAbort)
ON_COMMAND(ID_MACHINEPROPERTIES_SHUTDOWN_REBOOT, OnShutdownReboot)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMachineView construction/destruction
CMachineView::CMachineView()
{
// TODO: add construction code here
}
CMachineView::~CMachineView()
{
}
BOOL CMachineView::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= TVS_HASLINES |
TVS_LINESATROOT |
TVS_HASBUTTONS |
TVS_SHOWSELALWAYS;
return CTreeView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CMachineView drawing
void CMachineView::OnDraw(CDC* pDC)
{
CRemoteAdminDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
void CMachineView::OnInitialUpdate()
{
CTreeView::OnInitialUpdate();
// When being reused, reset the image list
ImageList_Destroy(m_ilMachine.Detach());
// When being reused, clean the tree control(view)
GetTreeCtrl().DeleteAllItems();
CreateEmptyTree();
GetTreeCtrl().SetIndent(5);
}
/////////////////////////////////////////////////////////////////////////////
// CMachineView diagnostics
#ifdef _DEBUG
void CMachineView::AssertValid() const
{
CTreeView::AssertValid();
}
void CMachineView::Dump(CDumpContext& dc) const
{
CTreeView::Dump(dc);
}
CRemoteAdminDoc* CMachineView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CRemoteAdminDoc)));
return (CRemoteAdminDoc*)m_pDocument;
}
#endif //_DEBUG
void CMachineView::CreateEmptyTree()
{
CreateImageList();
CreateTreeRoot();
}
void CMachineView::CreateImageList()
{
// Load various icons required for the machine view
HICON hIconMachineOnNetwork = ::AfxGetApp()->LoadIcon(MAKEINTRESOURCE(IDI_MACHINE_ON_NETWORK));
HICON hIconMachine = ::AfxGetApp()->LoadIcon(MAKEINTRESOURCE(IDI_MACHINE));
// The imageslist is created
m_ilMachine.Create(20, 20, ILC_COLOR32 | ILC_MASK, 0, 1);
// Add the icons in the imagelist
m_ilMachine.Add(hIconMachineOnNetwork);
m_ilMachine.Add(hIconMachine);
// Add the imagelist to the tree control
GetTreeCtrl().SetImageList(&m_ilMachine, TVSIL_NORMAL);
}
void CMachineView::CreateTreeRoot()
{
CTreeCtrl& ptcVehicleView = GetTreeCtrl();
TVINSERTSTRUCT tviHelper = {0};
CString str;
//------------------------------------
// Create the root of the vehicle view
//------------------------------------
tviHelper.hParent = TVI_ROOT;
tviHelper.hInsertAfter = TVI_FIRST;
tviHelper.item.mask = TVIF_TEXT |
TVIF_IMAGE |
TVIF_SELECTEDIMAGE |
TVIF_PARAM;
str.LoadString(IDS_MONITORED_MACHINES);
tviHelper.item.pszText = str.GetBuffer(0);
tviHelper.item.iImage = MACHINE_IMAGE_ON_NETWORK;
tviHelper.item.iSelectedImage = MACHINE_IMAGE_ON_NETWORK;
tviHelper.item.lParam = 0;
m_hMachineViewRoot = ptcVehicleView.InsertItem(&tviHelper);
}
void CMachineView::OnRButtonDown(UINT nFlags, CPoint point)
{
CTreeView::OnLButtonDown(nFlags, point);
HTREEITEM hTreeItem;
CMenu menuContext;
CPoint t_point;
CRect t_Rect;
TVITEM tvItem;
TCHAR szText[_MAX_PATH] = _T("");
tvItem.pszText = szText;
t_point = point;
SetFocus();
hTreeItem = GetTreeCtrl().HitTest(t_point, &nFlags); // See if any item has been it?
if(hTreeItem != NULL)
{/*
CString strIP = GetSelectedItemTextInTreeView();
if (strIP != _T(""))
{
if (strIP == _T("0"))
{
::GetRemoteAdminView()->GetListCtrl().DeleteAllItems();
}
else
{
RefreshProcesses(strIP);
}
}*/
// Check if the item clicked was not the root, it's associated LPARAM
// value is zero.
tvItem.hItem = hTreeItem;
tvItem.mask = TVIF_PARAM | TVIF_HANDLE;
GetTreeCtrl().GetItem(&tvItem);
if (tvItem.lParam == 0)
{
BOOL bResult = GetTreeCtrl().GetItemRect(hTreeItem, &t_Rect, TRUE);
if(t_Rect.PtInRect(t_point))
{
GetTreeCtrl().SelectItem(hTreeItem);
ClientToScreen(&t_point);
MFC_DocView::GetRemoteAdminView()->GetListCtrl().DeleteAllItems();
menuContext.LoadMenu(IDR_MACHINE_OPTIONS);
CMenu* pMenu = menuContext.GetSubMenu(0);
pMenu->TrackPopupMenu(TPM_LEFTALIGN, t_point.x, t_point.y, this);
}
}
else
{
CString strIP = GetTreeCtrl().GetItemText(hTreeItem);
BOOL bResult = GetTreeCtrl().GetItemRect(hTreeItem, &t_Rect, TRUE);
if(t_Rect.PtInRect(t_point))
{
GetTreeCtrl().SelectItem(hTreeItem);
ClientToScreen(&t_point);
// Refress the process when even right clicked
RefreshProcesses(strIP);
menuContext.LoadMenu(IDR_MACHINE_PROPERTIES);
CMenu* pMenu = menuContext.GetSubMenu(0);
pMenu->TrackPopupMenu(TPM_LEFTALIGN, t_point.x, t_point.y, this);
}
}
}
}
void CMachineView::OnAddMachine()
{
CRemoteLogonDlg dlgRemoteLogon;
if (dlgRemoteLogon.DoModal() == IDOK)
{
BOOL bAddMachineSuccess = AddMachine(dlgRemoteLogon.m_strRemoteIP, dlgRemoteLogon.m_strPassword, GetDocument(), MFC_DocView::GetRemoteAdminView());
// Show visual progress, if successful
if (bAddMachineSuccess)
{
MFC_DocView::GetAppDocument()->CreateVisualThread();
}
}
}
BOOL CMachineView::AddMachine(CString strIP, CString strPassword, CRemoteAdminDoc* pRemoteAdminDoc, CRemoteAdminView* pRemoteAdminView)
{
if (GetDocument()->CheckIfMachinePresent(strIP) == FALSE)
{
SConnectInfo* pConnectInfo = new SConnectInfo;
pConnectInfo->pDoc = pRemoteAdminDoc;
pConnectInfo->pMachineView = this;
pConnectInfo->pRemoteAdminView = pRemoteAdminView;
pConnectInfo->strIP = strIP;
pConnectInfo->strPwd = strPassword;
unsigned threadID = 0;
// Check if a thread is not processing a machine
if (pRemoteAdminDoc->IsConnectionPending(strIP) == FALSE)
{
::_beginthreadex(NULL, 0, ThreadConnection::ConnectToMachine, pConnectInfo, 0, &threadID);
return TRUE;
}
else
{
CString strFormattedErrorMsg = ErrorHandling::ConvertStringTableIDToErrorMsg(strIP, IDS_CONNECTION_PENDING);
::AfxMessageBox(strFormattedErrorMsg);
}
}
else
{
CString strFormattedErrorMsg = ErrorHandling::ConvertStringTableIDToErrorMsg(strIP, IDS_MACHINE_ALREADY_PRESENT);
::AfxMessageBox(strFormattedErrorMsg);
}
return FALSE;
}
void CMachineView::OnDeleteMachine()
{
TCHAR szText[_MAX_PATH] = _T("");
TVITEM tvItem = {0};
HTREEITEM hMachineToBeDeleted = GetTreeCtrl().GetSelectedItem();
/*tvItem.hItem = hMachineToBeDeleted;
tvItem.pszText = szText;
tvItem.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_TEXT;
GetTreeCtrl().GetItem(&tvItem);
GetTreeCtrl().GetItemText(hMachineToBeDeleted);
CMachineInfo* pMachineInfo = reinterpret_cast<CMachineInfo*>(tvItem.lParam);*/
CString strIP = GetTreeCtrl().GetItemText(hMachineToBeDeleted);
DeleteMachineFromBeingMonitored(strIP, MFC_DocView::GetRemoteAdminView());
}
void CMachineView::DeleteMachineFromBeingMonitored(CString strIP, CRemoteAdminView* pRemoteAdminView)
{
// Disconnects the machine and frees the machine info from the internal list
GetDocument()->DeleteAndDisconnectMachine(strIP);
// Get the HTREEITEM for the IP
HTREEITEM hMachineToBeDeleted = GetTreeItemForText(strIP);
// Remove from machine from the tree
DeleteMachineFromTree(hMachineToBeDeleted);
// Clear the processes in the list view
//::GetRemoteAdminView()->GetListCtrl().DeleteAllItems();
pRemoteAdminView->GetListCtrl().DeleteAllItems();
// Select the root item
GetTreeCtrl().SelectItem(m_hMachineViewRoot);
// Since the root gets selected, delete all in the remote admin view, as the
// root does not show any info
//::GetRemoteAdminView()->GetListCtrl().DeleteAllItems();
pRemoteAdminView->GetListCtrl().DeleteAllItems();
}
HTREEITEM CMachineView::ShowNewMachine(CString strTextToBeShown, CMachineInfo* pMachineInfo)
{
TVINSERTSTRUCT tviHelper = {0};
// Show a new machine in the hierarchy
tviHelper.hParent = m_hMachineViewRoot;
tviHelper.hInsertAfter = TVI_LAST;
tviHelper.item.mask = TVIF_TEXT |
TVIF_IMAGE |
TVIF_SELECTEDIMAGE |
TVIF_PARAM;
tviHelper.item.pszText = strTextToBeShown.GetBuffer(0);
tviHelper.item.iImage = MACHINE_IMAGE;
tviHelper.item.iSelectedImage = MACHINE_IMAGE;
tviHelper.item.lParam = reinterpret_cast<LPARAM>(pMachineInfo);
HTREEITEM hNewTreeItem = GetTreeCtrl().InsertItem(&tviHelper);
// Expand the root to show the new machine
GetTreeCtrl().Expand(m_hMachineViewRoot, TVE_EXPAND);
return hNewTreeItem;
}
void CMachineView::DeleteMachineFromTree(HTREEITEM hMachineToBeDeleted)
{
GetTreeCtrl().DeleteItem(hMachineToBeDeleted);
}
void CMachineView::OnRefreshProcess()
{
HTREEITEM hSelectedIntem = GetTreeCtrl().GetSelectedItem();
TVITEM tvItem = {0};
TCHAR szText[_MAX_PATH] = _T("");
tvItem.hItem = hSelectedIntem;
tvItem.mask = TVIF_TEXT | TVIF_HANDLE;
tvItem.pszText = szText;
tvItem.cchTextMax = _MAX_PATH;
GetTreeCtrl().GetItem(&tvItem);
RefreshProcesses(tvItem.pszText);
}
void CMachineView::OnLButtonDown(UINT nFlags, CPoint point)
{
HTREEITEM hTreeItem = GetTreeCtrl().HitTest(point, NULL); // See if any item has been it?
if (hTreeItem != NULL)
{
TVITEM tvItem = {0};
TCHAR szText[_MAX_PATH] = _T("");
tvItem.hItem = hTreeItem;
tvItem.mask = TVIF_HANDLE | TVIF_PARAM;
tvItem.pszText = szText;
tvItem.cchTextMax = _MAX_PATH;
GetTreeCtrl().GetItem(&tvItem);
if (tvItem.lParam == 0) // The root has 0 (zero) in it's lParam member
{
// Clear the list view when clicked on the root
MFC_DocView::GetRemoteAdminView()->GetListCtrl().DeleteAllItems();
}
else
{
tvItem.hItem = hTreeItem;
tvItem.mask = TVIF_HANDLE | TVIF_TEXT;
GetTreeCtrl().GetItem(&tvItem);
RefreshProcesses(tvItem.pszText);
}
}
CTreeView::OnLButtonDown(nFlags, point);
}
void CMachineView::RefreshProcesses(CString strRemoteMachineIP)
{
// Refresh the view to show the new processes
(MFC_DocView::GetRemoteAdminView())->RefreshProcesses(strRemoteMachineIP);
}
void CMachineView::OnExecuteProcess()
{
// Get the selected item text, i.e IP of the machine
TVITEM tvItem = {0};
TCHAR szText[_MAX_PATH] = _T("");
tvItem.hItem = GetTreeCtrl().GetSelectedItem();
tvItem.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_PARAM;
tvItem.pszText = szText;
tvItem.cchTextMax = _MAX_PATH;
GetTreeCtrl().GetItem(&tvItem);
CRemoteProcessDlg dlgRemoteProcess;
if (dlgRemoteProcess.DoModal() == IDOK)
{
HANDLE hRemoteAdminProcessExecutePipe = GetDocument()->GetRemoteAdminProcessExecutePipe(tvItem.pszText);
if (hRemoteAdminProcessExecutePipe != NULL)
{
// Send a command to continue the thread that will execute the remote process
SCommand cmd;
cmd.m_bThreadExit = FALSE;
// Execute the command on the remote machine with the following parameters
SExecuteCommand ExeCmd = {0};
::memcpy(ExeCmd.m_szDomain, dlgRemoteProcess.m_strDomain.GetBuffer(0), _MAX_PATH);
::memcpy(ExeCmd.m_szPassword, dlgRemoteProcess.m_strPassword.GetBuffer(0), _MAX_PATH);
::memcpy(ExeCmd.m_szProcessPath, dlgRemoteProcess.m_strProcessPath.GetBuffer(0), _MAX_PATH);
::memcpy(ExeCmd.m_szUsername, dlgRemoteProcess.m_strUser.GetBuffer(0), _MAX_PATH);
BOOL bOk = FALSE;
DWORD dwWritten = 0;
bOk = ::WriteFile(hRemoteAdminProcessExecutePipe, &cmd, sizeof(SCommand), &dwWritten, NULL);
bOk = ::WriteFile(hRemoteAdminProcessExecutePipe, &ExeCmd, sizeof(SExecuteCommand), &dwWritten, NULL);
TCHAR szMessage[_MAX_PATH] = _T("");
DWORD dwRead = 0;
// Wait for process triggering acknowledgement.
bOk = ::ReadFile(hRemoteAdminProcessExecutePipe, szMessage, sizeof(szMessage), &dwRead, NULL);
// There is some message that the process triggering was not sucessful
// If it had been the string would be ""
if (::strcmp(szMessage, _T("")) != 0)
{
CString strFormattedErrorMsg = ErrorHandling::ConvertStringTableIDToErrorMsg(tvItem.pszText, IDS_NOT_START_REMOTE_PROCESS);
::AfxMessageBox(strFormattedErrorMsg);
}
}
}
}
CString CMachineView::GetSelectedItemTextInTreeView()
{
HTREEITEM hSelectedItem = NULL;
// Get the IP of the selected item
hSelectedItem = GetTreeCtrl().GetSelectedItem();
TVITEM tvItem = {0};
tvItem.hItem = hSelectedItem;
tvItem.mask = TVIF_PARAM | TVIF_HANDLE ;
GetTreeCtrl().GetItem(&tvItem);
// If the root is not the current selection, then some IP is selected.
// Return zero (0), if the root is selected, else get the selected item, which
// will be the IP. LPARAM in the tree view item for root is zero.
if (tvItem.lParam == 0)
{
return _T("0");
}
else
{
return GetTreeCtrl().GetItemText(hSelectedItem);
}
return _T("");
}
HTREEITEM CMachineView::GetTreeItemForText(CString strText)
{
HTREEITEM hCurrent = GetTreeCtrl().GetNextItem(m_hMachineViewRoot, TVGN_CHILD);
while (hCurrent != NULL)
{
// Get the text for the item. Notice we use TVIF_TEXT because
// we want to retrieve only the text, but also specify TVIF_HANDLE
// because we're getting the item by its handle.
TVITEM item;
TCHAR szText[1024];
item.hItem = hCurrent;
item.mask = TVIF_TEXT | TVIF_HANDLE;
item.pszText = szText;
item.cchTextMax = 1024;
BOOL bWorked = GetTreeCtrl().GetItem(&item);
if (bWorked)
{
if (::strcmp(strText.GetBuffer(0), item.pszText) == 0)
{
return hCurrent;
}
}
// Try to get the next item
hCurrent = GetTreeCtrl().GetNextItem(hCurrent, TVGN_NEXT);
}
// Cannot find the tree item with the strText;
ASSERT(NULL);
return NULL;
}
void CMachineView::OnShutdownHalt()
{
CString strIP = GetSelectedItemTextInTreeView();
HANDLE hRemoteAdminSysShutDownPipe = GetDocument()->GetRemoteAdminSysShutDownPipe(strIP);
if (hRemoteAdminSysShutDownPipe != NULL)
{
extern UINT g_iShutdownDelay; // Time given to shutdown, updated by the CTimeSettingsDlg
SCommand cmd = {0};
cmd.m_bThreadExit = FALSE;
SSysShutDownInfo shutdownInfo = {0};
shutdownInfo.bReboot = FALSE;
shutdownInfo.bShutDown = TRUE;
shutdownInfo.iTimeToShutDown = g_iShutdownDelay/1000; // we require time in secs.
DWORD dwWritten = 0;
DWORD dwRead = 0;
BOOL bOk = FALSE;
TCHAR szMessage[_MAX_PATH] = _T("");
bOk = ::WriteFile(hRemoteAdminSysShutDownPipe, &cmd, sizeof(SCommand), &dwWritten, NULL);
bOk = ::WriteFile(hRemoteAdminSysShutDownPipe, &shutdownInfo, sizeof(SSysShutDownInfo), &dwWritten, NULL);
bOk = ::ReadFile(hRemoteAdminSysShutDownPipe, szMessage, sizeof(szMessage), &dwRead, NULL);
// There is some message that the process triggering was not sucessful
// If it had been the string would be ""
if (::strcmp(szMessage, _T("")) != 0)
{
::AfxMessageBox(szMessage);
}
}
}
void CMachineView::OnShutdownReboot()
{
CString strIP = GetSelectedItemTextInTreeView();
HANDLE hRemoteAdminSysShutDownPipe = GetDocument()->GetRemoteAdminSysShutDownPipe(strIP);
if (hRemoteAdminSysShutDownPipe != NULL)
{
extern UINT g_iShutdownDelay; // Time given to shutdown, updated by the CTimeSettingsDlg
// No need to quit the thread on the server side
SCommand cmd = {0};
cmd.m_bThreadExit = FALSE;
// Fill the system shutdown requirements structure
SSysShutDownInfo shutdownInfo = {0};
shutdownInfo.bReboot = TRUE;
shutdownInfo.bShutDown = TRUE;
shutdownInfo.iTimeToShutDown = g_iShutdownDelay/1000; // we require time in secs.
DWORD dwWritten = 0;
DWORD dwRead = 0;
BOOL bOk = FALSE;
TCHAR szMessage[_MAX_PATH] = _T("");
bOk = ::WriteFile(hRemoteAdminSysShutDownPipe, &cmd, sizeof(SCommand), &dwWritten, NULL);
bOk = ::WriteFile(hRemoteAdminSysShutDownPipe, &shutdownInfo, sizeof(SSysShutDownInfo), &dwWritten, NULL);
bOk = ::ReadFile(hRemoteAdminSysShutDownPipe, szMessage, sizeof(szMessage), &dwRead, NULL);
// There is some message that the process triggering was not sucessful
// If it had been the string would be ""
if (::strcmp(szMessage, _T("")) != 0)
{
::AfxMessageBox(szMessage);
}
}
}
void CMachineView::OnShutdownAbort()
{
CString strIP = GetSelectedItemTextInTreeView();
HANDLE hRemoteAdminSysShutDownPipe = GetDocument()->GetRemoteAdminSysShutDownPipe(strIP);
if (hRemoteAdminSysShutDownPipe != NULL)
{
SCommand cmd = {0};
cmd.m_bThreadExit = FALSE;
SSysShutDownInfo shutdownInfo = {0};
shutdownInfo.bShutDown = FALSE;
DWORD dwWritten = 0;
DWORD dwRead = 0;
BOOL bOk = FALSE;
TCHAR szMessage[_MAX_PATH] = _T("");
bOk = ::WriteFile(hRemoteAdminSysShutDownPipe, &cmd, sizeof(SCommand), &dwWritten, NULL);
bOk = ::WriteFile(hRemoteAdminSysShutDownPipe, &shutdownInfo, sizeof(SSysShutDownInfo), &dwWritten, NULL);
bOk = ::ReadFile(hRemoteAdminSysShutDownPipe, szMessage, sizeof(szMessage), &dwRead, NULL);
// There is some message that the process triggering was not sucessful
// If it had been the string would be ""
if (::strcmp(szMessage, _T("")) != 0)
{
::AfxMessageBox(szMessage);
}
}
}