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
Control certain aspects of machines sitting remotely, without having to install and trigger an application on the remote machine.
// 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);
        }
    }
}
    

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)

About the Author

Prateek Kaul
Web Developer
India India
No Biography provided

| Advertise | Privacy | Mobile
Web04 | 2.8.140718.1 | Last Updated 1 Apr 2012
Article Copyright 2003 by Prateek Kaul
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid