Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Remote Processes and Machine control of Windows NT based systems (2000/XP)

, 1 Apr 2012 CPOL
Control certain aspects of machines sitting remotely, without having to install and trigger an application on the remote machine.
// RemoteAdminDoc.cpp : implementation of the CRemoteAdminDoc class
//

#include "stdafx.h"
#include "RemoteAdminDoc.h"
#include "MachineInfo.h"
#include "GlobalMFCHelperFunc.h"
#include "GlobalHelperFunc.h"
#include "MachineView.h"
#include "resource.h"
#include "RemoteAdminView.h"
#include "MainFrame.h"
#include "RemoteAdmin.h"
#include "ProgressWndThread.h"
#include "ProcessUpdate.h"
#include "ConnectionThread.h"
#include <process.h>

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


extern CRITICAL_SECTION g_CriticalSection;
/////////////////////////////////////////////////////////////////////////////
// CRemoteAdminDoc

IMPLEMENT_DYNCREATE(CRemoteAdminDoc, CDocument)

BEGIN_MESSAGE_MAP(CRemoteAdminDoc, CDocument)
	//{{AFX_MSG_MAP(CRemoteAdminDoc)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRemoteAdminDoc construction/destruction

CRemoteAdminDoc::CRemoteAdminDoc()
{
	m_hUpdateProcessList    = NULL;
	m_pVisualProgressThread = NULL;
}

CRemoteAdminDoc::~CRemoteAdminDoc()
{
}

BOOL CRemoteAdminDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;
	
    unsigned int threadID;

    /*
    m_threadForUpdateProcessList = ::AfxBeginThread(
                                        UpdateProcessListForAllMachines, 
                                        this, 
                                        THREAD_PRIORITY_NORMAL, 
                                        0,
                                        CREATE_SUSPENDED
    */                                       // );

	// Prepare the SDocView structure to pass wrapped pointers values of the
	// document, view(s), mainframe. They are being sent this way as a worker thread
	// can't call the functions UI (GetMachineView, GetMainFrame  etc)
	// involving windows, because of crashes, hence this workaround!
    SDocView* pDocView         = new SDocView;
    pDocView->pDoc             = this;
    pDocView->pMachineView     = MFC_DocView::GetMachineView();
    pDocView->pRemoteAdminView = MFC_DocView::GetRemoteAdminView();

    m_hUpdateProcessList = reinterpret_cast<HANDLE>(::_beginthreadex(
                                                        NULL, 
                                                        0, 
														ProcessUpdate::UpdateProcessListForAllMachines, 
                                                        pDocView, 
                                                        CREATE_SUSPENDED, 
                                                        &threadID)
                                                        );

	return TRUE;
}


void CRemoteAdminDoc::CreateVisualThread()
{
	if (m_pVisualProgressThread == NULL)
	{
		m_pVisualProgressThread = static_cast<CProgressWndThread*>(::AfxBeginThread(RUNTIME_CLASS(CProgressWndThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED));

		if (m_pVisualProgressThread != NULL)
		{
			m_pVisualProgressThread->SetDocument(this);
			m_pVisualProgressThread->ResumeThread();
		}
	}
}



/////////////////////////////////////////////////////////////////////////////
// CRemoteAdminDoc serialization

void CRemoteAdminDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
        CString* pstrConnctedMachinesIP = NULL;
        int iNumberOfConnectedMachines  = 0;

        GetConnectedMachinesIP(&pstrConnctedMachinesIP, &iNumberOfConnectedMachines);
		
        // Serialize the number of machines last beging monitored
        ar << iNumberOfConnectedMachines;

        // Serialize the Machine Informations
        for (int i = 0; i < iNumberOfConnectedMachines; ++i)
        {
            CMachineInfo* pMachineInfo = m_RemoteAdministrator.GetMachineInfo(pstrConnctedMachinesIP[i]);
            ar << pMachineInfo;
        }

		// Free memory
		if (pstrConnctedMachinesIP != NULL)
		{
			delete[] pstrConnctedMachinesIP;
		}
	}
	else
	{
        m_milInfoReadFromArchiveList   = new CMachineInfoList;
        int iNumberOfConnectedMachines = 0;
        CMachineInfo* pMachineInfo     = NULL;
		
        ar >> iNumberOfConnectedMachines;

        for (int i = 0; i < iNumberOfConnectedMachines; ++i)
        {
            ar >> pMachineInfo;
            m_milInfoReadFromArchiveList->AddTail(pMachineInfo);
        }
	}
}


/////////////////////////////////////////////////////////////////////////////
// CRemoteAdminDoc diagnostics

#ifdef _DEBUG
void CRemoteAdminDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CRemoteAdminDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG


void CRemoteAdminDoc::AddMachine(CMachineInfo& miMachineInfo)
{
    m_RemoteAdministrator.AddMachine(miMachineInfo);
}

void CRemoteAdminDoc::DeleteMachine(CMachineInfo& miMachineInfo)
{
    m_RemoteAdministrator.DeleteMachine(miMachineInfo);
}

BOOL CRemoteAdminDoc::CheckIfMachinePresent(CString strIP)
{
    BOOL bSuccess = m_RemoteAdministrator.CheckIfMachinePresent(strIP);

    return bSuccess;
}

BOOL CRemoteAdminDoc::EstablishAllConnections(CString strRemoteMachineIP, CString strPwd, BOOL bEstablish, CMachineView* pMachineView, CRemoteAdminView* pRemoteAdminView)
{
    ASSERT(pRemoteAdminView);
    ASSERT(pMachineView);
    
    BOOL bConnectionSuccess      = FALSE;
    BOOL bCopyServiceExe         = FALSE;
    BOOL bStartAndInstallService = FALSE;
    BOOL bConnectToRemoteService = FALSE;

    // The service may be running already, so try to connect directly
    bConnectToRemoteService = ConnectToRemoteService(strRemoteMachineIP, strPwd, pMachineView, pRemoteAdminView);

    if (!bConnectToRemoteService)
    {
        bConnectionSuccess = m_RemoteAdministrator.EstablishAllConnections(strRemoteMachineIP, strPwd, bEstablish);
		if (!bConnectionSuccess)
		{
			CString strFormattedErrorMsg = ErrorHandling::ConvertStringTableIDToErrorMsg(strRemoteMachineIP, IDS_CONNECTION_NOT_ESTABLISHED);

			//CRemoteAdminApp* pApp = static_cast<CRemoteAdminApp*>(::AfxGetApp());
			(MFC_DocView::GetApp())->ShowBalloonMsgInTray(_T("Remote connection error !"), strFormattedErrorMsg);
		}


		bCopyServiceExe = m_RemoteAdministrator.CopyServiceExeToRemoteMachine(strRemoteMachineIP);
		if (!bCopyServiceExe)
		{
			CString strFormattedErrorMsg = ErrorHandling::ConvertStringTableIDToErrorMsg(strRemoteMachineIP, IDS_NOT_COPY_SERVICE_EXE);

			//CRemoteAdminApp* pApp = static_cast<CRemoteAdminApp*>(::AfxGetApp());
			(MFC_DocView::GetApp())->ShowBalloonMsgInTray(_T("Service executable copying error !"), strFormattedErrorMsg);
		}


        bStartAndInstallService = m_RemoteAdministrator.InstallAndStartRemoteService(strRemoteMachineIP);
		if (!bStartAndInstallService)
		{
			CString strFormattedErrorMsg = ErrorHandling::ConvertStringTableIDToErrorMsg(strRemoteMachineIP, IDS_NOT_START_SERVICE);

			//CRemoteAdminApp* pApp = static_cast<CRemoteAdminApp*>(::AfxGetApp());
			(MFC_DocView::GetApp())->ShowBalloonMsgInTray(_T("Remote service starting error !"), strFormattedErrorMsg);
		}
		
		// Do some time pass, for stabilization at the remote end
        ::Sleep(2000);

        bConnectToRemoteService = ConnectToRemoteService(strRemoteMachineIP, strPwd, pMachineView, pRemoteAdminView);
		if (!bConnectToRemoteService)
		{
			CString strFormattedErrorMsg = ErrorHandling::ConvertStringTableIDToErrorMsg(strRemoteMachineIP, IDS_NO_CONNECT_TO_REMOTE_SERVICE);

			//CRemoteAdminApp* pApp = static_cast<CRemoteAdminApp*>(::AfxGetApp());
			(MFC_DocView::GetApp())->ShowBalloonMsgInTray(_T("Connection error !"), strFormattedErrorMsg);
		}

        if (bConnectionSuccess && bCopyServiceExe && bStartAndInstallService && bConnectToRemoteService)
        {
            return TRUE;            
        }
    }

    return bConnectToRemoteService;
}

BOOL CRemoteAdminDoc::CopyServiceExeToRemoteMachine(CString strRemoteMachineIP)
{
    return m_RemoteAdministrator.CopyServiceExeToRemoteMachine(strRemoteMachineIP);
}

void CRemoteAdminDoc::RefreshProcessList(CString strRemoteMachineIP, CProcessInfoList& pilList)
{
    m_RemoteAdministrator.RefreshProcessList(strRemoteMachineIP, pilList);
}

CProcessInfoList* CRemoteAdminDoc::GetProcessInfoList(CString strRemoteMachineIP)
{
    return m_RemoteAdministrator.GetProcessInfoList(strRemoteMachineIP);
}

void CRemoteAdminDoc::DeleteAndDisconnectAllMachines()
{
    m_RemoteAdministrator.DeleteAndDisconnectAllMachines();
}

void CRemoteAdminDoc::DeleteAndDisconnectMachine(CString strRemoteAdminMachine)
{
    m_RemoteAdministrator.DeleteAndDisconnectMachine(strRemoteAdminMachine);
}

void CRemoteAdminDoc::OnCloseDocument() 
{
	DeleteAndDisconnectAllMachines();
	
	CDocument::OnCloseDocument();
}

BOOL CRemoteAdminDoc::ConnectToRemoteService(CString strRemoteMachineIP, CString strPwd, CMachineView* pMachineView, CRemoteAdminView* pRemoteAdminView)
{
    CMachineInfo* pMachineInfo = new CMachineInfo;

    pMachineInfo->SetLogon(_T("Administrator"));
    pMachineInfo->SetIP(strRemoteMachineIP);
    pMachineInfo->SetPassword(strPwd);
    m_RemoteAdministrator.AddMachine(*pMachineInfo);

    BOOL bConnectToRemoteService = FALSE;
    bConnectToRemoteService = m_RemoteAdministrator.ConnectToRemoteService(strRemoteMachineIP, 1, 0);

    if (bConnectToRemoteService)
    {
        pMachineView->ShowNewMachine(strRemoteMachineIP, pMachineInfo);
        
        HTREEITEM h = pMachineView->GetTreeItemForText(strRemoteMachineIP);
        if (h != NULL)
        {
            pMachineView->GetTreeCtrl().Select(h, TVGN_CARET);
            pRemoteAdminView->GetListCtrl().DeleteAllItems();
            pRemoteAdminView->GetListCtrl().InsertItem(0, _T("Refreshing process list..."));
   
            ::Sleep(2000);   
			
			if (pMachineInfo)
			{
				delete pMachineInfo;
			}
				

            return TRUE;
        }
        else
        {
			if (pMachineInfo)
			{
				delete pMachineInfo;
			}
            return FALSE;
        }
    }
    else
    {
        m_RemoteAdministrator.DeleteMachine(*pMachineInfo);

		if (pMachineInfo)
		{
			delete pMachineInfo;
		}

        return FALSE;
    }
}

void CRemoteAdminDoc::GetConnectedMachinesIP(CString** pstrConnctedMachinesIP /*out*/, int* piNumberOfConnectedMachines/*out*/)
{
    m_RemoteAdministrator.GetConnectedMachinesIP(pstrConnctedMachinesIP, piNumberOfConnectedMachines);
}

int CRemoteAdminDoc::GetTotalMachinesMonitored()
{
    return m_RemoteAdministrator.GetTotalMachinesMonitored();
}

BOOL CRemoteAdminDoc::AddToConnectionPendingList(CString strIP)
{
    return m_RemoteAdministrator.AddToConnectionPendingList(strIP);
}

BOOL CRemoteAdminDoc::RemoveFromConnecionPendingList(CString strIP)
{
    return m_RemoteAdministrator.RemoveFromConnecionPendingList(strIP);
}

BOOL CRemoteAdminDoc::IsConnectionPending(CString strIP)
{
    return m_RemoteAdministrator.IsConnectionPending(strIP);
}

BOOL CRemoteAdminDoc::OnSaveDocument(LPCTSTR lpszPathName) 
{
	return CDocument::OnSaveDocument(lpszPathName);
}


BOOL CRemoteAdminDoc::OnOpenDocument(LPCTSTR lpszPathName) 
{
	// << BLOCK start
	// << Commented by Prateek Kaul on July 28, 2003.
	// It is better to make a clean exit (making the thread return), rather than terminating
	// the thread forcefully.
    // Kill the thread that is updating the process list
    /*if (m_hUpdateProcessList != NULL)
    {
        ::TerminateThread(m_hUpdateProcessList, 0);
        m_hUpdateProcessList = NULL;
    }*/
	// << BLOCK end

	// Make the ProcessUpdate::UpdateProcessListForAllMachines(), i.e the thread function
	// that updates the process list for all machines end (return gracefully)
	// by setting the flag, rather terminate it forcefully 
	extern BOOL g_bUpdateProcessList;
	g_bUpdateProcessList = FALSE;

	// Wait for few secs to allow the thread terminate, it may be in the middle of a
	// calculation
	::Sleep(3000);

	// No need to keep a track of the ProcessUpdate::UpdateProcessListForAllMachines() thread handle
	if (m_hUpdateProcessList != NULL)
    {
		m_hUpdateProcessList = NULL;
    }

	// Close all connections and clean up the data structures for all
	// connected machines
	DeleteAndDisconnectAllMachines();

	// Allow the new ProcessUpdate::UpdateProcessListForAllMachines() thread function, which will
	// be triggered below, to proceed gracefully.
	g_bUpdateProcessList = TRUE;

    if (!CDocument::OnOpenDocument(lpszPathName))
		return FALSE;

	// Since the MachineInfo List has been serailzed from
    // the archive, we need to make connections for the machines
    // in the list.
    CMachineInfo* pMachineInfo = NULL;
    POSITION pos = m_milInfoReadFromArchiveList->GetHeadPosition();

    // Start connections to the Machines whose CMachineInfo class have
    // been read from the archive. They have been read in the m_milInfoReadFromArchiveList.
    while (pos != NULL)
    {
        pMachineInfo = m_milInfoReadFromArchiveList->GetNext(pos);
       
        SConnectInfo* pConnectInfo     = new SConnectInfo;
        pConnectInfo->pDoc             = MFC_DocView::GetAppDocument();
        pConnectInfo->pMachineView     = MFC_DocView::GetMachineView();
        pConnectInfo->pRemoteAdminView = MFC_DocView::GetRemoteAdminView();
        pConnectInfo->strIP            = pMachineInfo->GetIP();
        pConnectInfo->strPwd           = pMachineInfo->GetPassword();

        // Start the thread that will process the connection
        unsigned threadID = 0;
        ::_beginthreadex(NULL, 0, ThreadConnection::ConnectToMachine, pConnectInfo, 0, &threadID);
    }
	
    // Since all machines have been read from the archive, dispose off the list.
    if (m_milInfoReadFromArchiveList != NULL)
    {
		CMachineInfo* pMachineInfo = NULL;
		POSITION pos = m_milInfoReadFromArchiveList->GetHeadPosition();
		while (pos != NULL)
		{
			pMachineInfo = m_milInfoReadFromArchiveList->GetNext(pos);

			ASSERT(pMachineInfo != NULL);

			if (pMachineInfo != NULL)
			{
				delete pMachineInfo;
			}
		}

        delete m_milInfoReadFromArchiveList;
        m_milInfoReadFromArchiveList = NULL;
    }
    
    // Now start the thread that retrieves the processes running on the remotely 
    // connected machines, in suspended state
    unsigned int threadID;
    SDocView* pDocView = new SDocView;
    pDocView->pDoc = this;
    pDocView->pMachineView = MFC_DocView::GetMachineView();
    pDocView->pRemoteAdminView = MFC_DocView::GetRemoteAdminView();

    m_hUpdateProcessList = reinterpret_cast<HANDLE>(::_beginthreadex(
                                                        NULL, 
                                                        0, 
                                                        ProcessUpdate::UpdateProcessListForAllMachines, 
                                                        pDocView, 
                                                        CREATE_SUSPENDED, 
                                                        &threadID)
                                                        );
	CreateVisualThread();

	return TRUE;
}

void CRemoteAdminDoc::DeleteContents() 
{
    DeleteAndDisconnectAllMachines();
    	
	CDocument::DeleteContents();
}

BOOL CRemoteAdminDoc::CanCloseFrame(CFrameWnd* pFrame) 
{
	// TODO: Add your specialized code here and/or call the base class
	
	return CDocument::CanCloseFrame(pFrame);
}

CString CRemoteAdminDoc::GetPasswordForMachine(CString strIP)
{
	return m_RemoteAdministrator.GetPassword(strIP);
}

BOOL CRemoteAdminDoc::AreConnectionsStillPending()
{
	UINT iMachines = m_RemoteAdministrator.GetNumberOfMachineConnectionsStillInProgress();

	if (iMachines == 0) // No connections pending...
	{
		return FALSE;
	}
	
	return TRUE;
}

UINT CRemoteAdminDoc::GetNumberOfMachineConnectionsStillInProgress()
{
	return m_RemoteAdministrator.GetNumberOfMachineConnectionsStillInProgress();
}

CString CRemoteAdminDoc::GetComputerNameFromIP(CString& strIP)
{
	return m_RemoteAdministrator.GetComputerNameFromIP(strIP);
}

CString CRemoteAdminDoc::GetComputerIPFromName(CString& strComputerName)
{
	return m_RemoteAdministrator.GetComputerIPFromName(strComputerName);
}

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)

Share

About the Author

Prateek Kaul
Web Developer
India India
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150414.1 | Last Updated 1 Apr 2012
Article Copyright 2003 by Prateek Kaul
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid