Click here to Skip to main content
15,884,473 members
Articles / Desktop Programming / MFC

How to write a simple but effective TCP/IP port scanner for Win32

Rate me:
Please Sign up or sign in to vote.
4.82/5 (15 votes)
27 Oct 20017 min read 162.8K   7.3K   101  
An article on how to write a TCP/IP port scanner with a GUI, based on the MFC's property sheet paradigm
/*
	CPropertySheetDialog.cpp
	Classe base per il dialogo basato sul property sheet.
	Luca Piergentili, 14/07/99
	lpiergentili@yahoo.com
	http://www.geocities.com/lpiergentili/
*/
#include "env.h"
#include "pragma.h"
#include <string.h>
#include "strcpyn.h"
#include <ctype.h>
#include "window.h"
#include "CPropertyPageList.h"
#include "CPropertyPageDialog.h"
#include "CPropertySheetDialog.h"
#include "CPropertySheetDialogMessages.h"
#include "resource.h"

IMPLEMENT_DYNCREATE(CPropertySheetDialog,CPropertySheet)

BEGIN_MESSAGE_MAP(CPropertySheetDialog,CPropertySheet)
	// bottoni dello sheet
	ON_BN_CLICKED(IDOK,OnOK)
	ON_BN_CLICKED(IDCANCEL,OnCancel)

	// menu di sistema
	ON_WM_SYSCOMMAND()

	// attivazione pagina
	ON_MESSAGE(WM_ACTIVATEPAGE,OnActivatePage)

	// bottoni dello sheet
	ON_MESSAGE(WM_SETPROPERTYSHEET_IDOKBUTTON,OnPropertySheetButton)
	ON_MESSAGE(WM_GETPROPERTYSHEET_IDOKBUTTON,OnPropertySheetButton)
	ON_MESSAGE(WM_SETPROPERTYSHEET_IDCANCELBUTTON,OnPropertySheetButton)
	ON_MESSAGE(WM_GETPROPERTYSHEET_IDCANCELBUTTON,OnPropertySheetButton)
	ON_MESSAGE(WM_ENABLEPROPERTYSHEET_IDOKBUTTON,OnPropertySheetButton)
	ON_MESSAGE(WM_DISABLEPROPERTYSHEET_IDOKBUTTON,OnPropertySheetButton)
	ON_MESSAGE(WM_ENABLEPROPERTYSHEET_IDCANCELBUTTON,OnPropertySheetButton)
	ON_MESSAGE(WM_DISABLEPROPERTYSHEET_IDCANCELBUTTON,OnPropertySheetButton)
END_MESSAGE_MAP()

/*
	CPropertySheetDialog()
*/
CPropertySheetDialog::CPropertySheetDialog(CWnd* pParentWnd,CPropertyPageList* pPropertyPageList) : CPropertySheet(" ",pParentWnd)
{
	// flag per esito costruttore
	m_bCreated = FALSE;

	// elimina il bottone Apply dello sheet
	this->CPropertySheet::m_psh.dwFlags = this->CPropertySheet::m_psh.dwFlags|PSH_NOAPPLYNOW;

	// crea le pagine presenti nella lista
	ITERATOR iter;
	PROPERTYPAGE* p;
	m_pPropertyPageList = pPropertyPageList;
	
	if((iter = m_pPropertyPageList->First())!=(ITERATOR)NULL)
		while(iter!=(ITERATOR)NULL)
		{
			p = (PROPERTYPAGE*)iter->data;
			if(p)
			{
				if(p->idd > 0)
					if(p->page)
					{
						CPropertyPageDialog* page = (CPropertyPageDialog*)p->page;

						// aggiunge la pagina allo sheet
						AddPage(page);
						
						// passa il puntatore alla lista delle pagine affinche' ogni pagina sia in grado di
						// accedere alle restanti
						page->SetPageList(m_pPropertyPageList);

						// passa il puntatore alla propria finestra affinche' ogni pagina sia in grado di
						// modificare il testo dei bottoni dello sheet (IDOK, IDCANCEL)
						// la chiamata deve essere effettuata nel costruttore perche' la OnInitDialog() chiama
						// la OnSetActive() della pagina di default e quest'ultima necessita il puntatore alla
						// finestra dello sheet
						page->SetPropertySheetWnd(this);
					}
			}

			iter = m_pPropertyPageList->Next(iter);
		}

	// puntatore alla pagina attiva quando viene cliccato IDOK
	m_pActivePageOnButtonClick = NULL;

	// flag per esito costruttore
	m_bCreated = TRUE;
}

/*
	OnSysCommand()

	Intercetta il messaggio di chiusura.
	La chiusura del dialogo puo' avvenire attraverso il bottone CANCEL (IDCANCEL), tramite ALT+F4 o
	tramite il menu di sistema.
	Per far si che lo sheet abbia un unico punto d'uscita, in modo tale da poter comunicare a ogni
	pagina che il dialogo sta per essere chiuso, deve essere intercettato il messaggio di chiusura
	(SC_CLOSE) e chiamato il gestore relativo (OnCancel()).
	Dato che la OnCancel() verifica il testo del bottone CANCEL (IDCANCEL), se riceve il messaggio
	di chiusura (SC_CLOSE), deve impostare il testo del bottone per l'uscita.
	La OnCancel() si occupa di chiamare la OnKillSheet() di ogni pagina in modo tale che ognuna possa
	eseguire il proprio codice di terminazione.
*/
void CPropertySheetDialog::OnSysCommand(UINT id,LPARAM lParam)
{
	// chiusura del dialogo (IDCANCEL, ALT+F4, menu di sistema)
	if((id & 0xFFF0)==SC_CLOSE)
	{
		// cambia il testo del bottone IDCANCEL da cancel in exit
		// (le pagine si comportano diversamente a seconda del testo del bottone)
		CWnd* pWnd;
		if((pWnd = GetDlgItem(IDCANCEL))!=NULL)
			pWnd->SetWindowText(IDCANCEL_EXIT_PROMPT);
		
		// termina, chiamando il codice relativo di ogni pagina
		CPropertySheetDialog::OnCancel();
	}

	// chiama il gestore originale
	CPropertySheet::OnSysCommand(id,lParam);
}

/*
	OnInitDialog()

	Inizializza il property sheet.
	Rimappa la funzione membro per modificare lo stile del dialogo.
*/
BOOL CPropertySheetDialog::OnInitDialog(void)
{
	// notare che la CPropertySheet::OnInitDialog() chiama la OnInitDialog() e la OnSetActive()
	// della pagina di default (la prima ad essere aggiunta con AddPage())
	CPropertySheet::OnInitDialog();

	// aggiungere n pixel per la barra di stato
	CRect rectOld;
	GetWindowRect(&rectOld);
	SetWindowPos(NULL,0,0,rectOld.Width(),rectOld.Height()/*+n*/,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);

	// menu
/*	CMenu menu;
	menu.LoadMenu(IDM_SERVICES);
	SetMenu(&menu);
	DrawMenuBar();
	menu.Detach();
*/

	// status bar
/*	RECT rect = {0,0,100,20};
	m_StatusBar.Create(WS_CHILD|WS_VISIBLE|CCS_BOTTOM,rect,this,0);
	static int parts[3] = {200,300,-1};
	m_StatusBar.SetParts(3,&parts[0]);
*/
	// modifica solo il testo del bottone IDCANCEL, il testo del bottone IDOK viene modificato
	// dalla OnSetActive() delle pagine
	CWnd* pWnd;
	if((pWnd = GetDlgItem(IDCANCEL))!=NULL)
		pWnd->SetWindowText(IDCANCEL_EXIT_PROMPT);

	// aggiunge il bottone per minimizzare lo sheet alla barra del titolo
	::SetWindowLong(m_hWnd,GWL_STYLE,GetStyle()|WS_MINIMIZEBOX);
	
	// aggiunge l'entrata per minimizzare al menu di sistema
	GetSystemMenu(FALSE)->InsertMenu((UINT)-1,MF_BYPOSITION|MF_STRING,SC_ICON,"Minimize");
	DrawMenuBar();

	return(TRUE);
}

/*
	OnOK()

	Gestore del bottone IDOK.
	Informa la pagina relativa del click sul bottone.
	Prima di informare la pagina ne aggiorna le variabili relative con quanto presente nel dialogo
	relativo, controllando che le pagina sia stata visualizzata perche' in caso contrario qualsiasi
	riferimento fallirebbe (handle nullo).
	Deve salvare il puntatore alla pagina (attiva) su cui e' stato cliccato IDOK affinche' la OnCancel()
	possa inviare il messaggio alla pagina giusta.
*/
void CPropertySheetDialog::OnOK(void)
{
	// ricava il puntatore alla pagina attiva
	CPropertyPage* pActivePage = GetActivePage();

	// salva il puntatore
	m_pActivePageOnButtonClick = pActivePage;

	// cerca la pagina nella lista, aggiornando le variabili membro
	// se vengono passati i controlli (DDV), informa la pagina del click su IDOK (invio del messaggio e
	// chiamata alla virtuale OnOk())
	ITERATOR iter;
	PROPERTYPAGE* p;
	if((iter = m_pPropertyPageList->First())!=(ITERATOR)NULL)
		while(iter!=(ITERATOR)NULL)
		{
			p = (PROPERTYPAGE*)iter->data;
			if(p)
			{
				if(p->idd > 0)
					if(p->page)
					{
						CPropertyPageDialog* page = (CPropertyPageDialog*)p->page;

						// confronta la pagina corrente con quella presente nella lista
						if(pActivePage->IsKindOf(p->runtimeclass))
						{
							// aggiorna le variabili membro della pagina con i campi del dialogo relativo
							if(page->UpdateData(TRUE))
								page->OnOk();
							break;
						}
					}
			}

			iter = m_pPropertyPageList->Next(iter);
		}
}

/*
	OnCancel()

	Gestore del bottone IDCANCEL.
	Informa la pagina relativa del click sul bottone.
	La funzione viene utilizzata per gestire i due prompt del bottone, Exit (default) e Cancel (impostato
	dalle pagine). A seconda del prompt del bottone invia il messaggio relativo (chiudere il dialogo o
	cancellare l'operazione corrente).
	Il gestore funziona come unico punto di uscita dello sheet, per cui si occupa di chiamare la OnKillSheet()
	di ogni pagina in modo tale che ognuna di esse possa eseguire il proprio codice di terminazione.
*/
void CPropertySheetDialog::OnCancel(void)
{
	CWnd* pWnd;
	CString cText;

	// ricava il puntatore alla pagina attiva e la imposta come corrente
	// il puntatore non e' relativo alla pagina correntemente visualizzata, ma a quella su cui e' stato
	// cliccato IDOK: in tal modo puo' inviare il WM_CANCEL alla pagina giusta dato la pagina corrente
	// (visualizzata) puo' non corrispondere a quella attiva (che ha ricevuto l'IDOK)
	// esempio: mentre sta' svolgendo il task relativo alla prima pagina, l'utente si sposta sulla seconda
	// e da li effettua il click su IDCANCEL
	CPropertyPage* pActivePage = (m_pActivePageOnButtonClick ? m_pActivePageOnButtonClick : GetActivePage());
	if(GetActivePage()!=pActivePage)
		SetActivePage(pActivePage);

	// ricava il puntatore al bottone
	if((pWnd = GetDlgItem(IDCANCEL))!=NULL)
	{
		// ricava il testo del bottone
		pWnd->GetWindowText(cText);
		
		// e' stata richiesta la chiusura del dialogo
		if(cText==IDCANCEL_EXIT_PROMPT)
		{
			ITERATOR iter;
			PROPERTYPAGE* p;

			if((iter = m_pPropertyPageList->First())!=(ITERATOR)NULL)
				while(iter!=(ITERATOR)NULL)
				{
					p = (PROPERTYPAGE*)iter->data;
					
					if(p->idd > 0)
						if(p->page)
						{
							CPropertyPageDialog* page = (CPropertyPageDialog*)p->page;
							if(page)
								page->OnKillSheet();
						}

					iter = m_pPropertyPageList->Next(iter);
				}

			// chiude il dialogo
			EndDialog(IDOK);
		}
		// e' stata richiesta la cancellazione dell'operazione corrente
		else if(cText==IDCANCEL_CANCEL_PROMPT)
		{
			ITERATOR iter;
			PROPERTYPAGE* p;

			if((iter = m_pPropertyPageList->First())!=(ITERATOR)NULL)
				while(iter!=(ITERATOR)NULL)
				{
					p = (PROPERTYPAGE*)iter->data;
					
					if(p->idd > 0)
						if(p->page)
						{
							CPropertyPageDialog* page = (CPropertyPageDialog*)p->page;
							if(page)
								if(pActivePage->IsKindOf(p->runtimeclass))
								{
									page->OnCancel();
									break;
								}
						}

					iter = m_pPropertyPageList->Next(iter);
				}
		}
		// chiude il dialogo e vaffanculo
		else
			EndDialog(IDCANCEL);
	}
}

/*
	OnActivatePage()
*/
LONG CPropertySheetDialog::OnActivatePage(UINT wParam,LONG /*lParam*/)
{
	int idd = (int)wParam;
	CPropertyPage* pActivePage = GetActivePage();

	ITERATOR iter;
	PROPERTYPAGE* p;
	if((iter = m_pPropertyPageList->First())!=(ITERATOR)NULL)
		while(iter!=(ITERATOR)NULL)
		{
			p = (PROPERTYPAGE*)iter->data;
			
			if(p->idd==idd)
				if(p->page)
					SetActivePage((CPropertyPage*)p->page);

			iter = m_pPropertyPageList->Next(iter);
		}

	SetActivePage(pActivePage);
	
	return(0);
}

/*
	SetSheetOkButtonText()

	Imposta il testo del bottone OK (IDOK) dello sheet.
*/
void CPropertySheetDialog::SetSheetOkButtonText(LPCSTR text)
{
	CWnd* pWnd;
	
	if((pWnd = GetDlgItem(IDOK))!=NULL)
	{
		pWnd->EnableWindow(TRUE);
		pWnd->SetWindowText(text);
	}
}

/*
	GetSheetOkButtonText()

	Ricava il testo del bottone OK (IDOK) dello sheet.
*/
LPCSTR CPropertySheetDialog::GetSheetOkButtonText(void)
{
	CWnd* pWnd;
	static char text[32];
	
	if((pWnd = GetDlgItem(IDOK))!=NULL)
	{
		pWnd->EnableWindow(TRUE);
		pWnd->GetWindowText(text,sizeof(text)-1);
	}

	return(text);
}

/*
	EnableSheetButtons()

	Abilita il bottone OK (IDOK) e cambia il testo del bottone CANCEL (IDCANCEL) con IDCANCEL_EXIT_PROMPT
	o con quanto passato dal chiamante.
*/
void CPropertySheetDialog::EnableSheetButtons(LPCSTR text)
{
	CWnd* pWnd;
	
	if((pWnd = GetDlgItem(IDOK))!=NULL)
		pWnd->EnableWindow(TRUE);
	if((pWnd = GetDlgItem(IDCANCEL))!=NULL)
		pWnd->SetWindowText(text ? text : IDCANCEL_EXIT_PROMPT);
}

/*
	DisableSheetButtons()

	Disabilita il bottone OK (IDOK) e cambia il testo del bottone CANCEL (IDCANCEL) con IDCANCEL_CANCEL_PROMPT
	o con quanto passato dal chiamante.
*/
void CPropertySheetDialog::DisableSheetButtons(LPCSTR text)
{
	CWnd* pWnd;

	if((pWnd = GetDlgItem(IDOK))!=NULL)
		pWnd->EnableWindow(FALSE);
	if((pWnd = GetDlgItem(IDCANCEL))!=NULL)
		pWnd->SetWindowText(text ? text : IDCANCEL_CANCEL_PROMPT);
}

/*
	On...()
*/
LONG CPropertySheetDialog::OnSetSheetOkButtonText(UINT /*wParam*/,LONG lParam)
{
	SetSheetOkButtonText((const char*)lParam);
	return(0);
}

LONG CPropertySheetDialog::OnGetSheetOkButtonText(UINT /*wParam*/,LONG lParam)
{
	strcpy((char*)lParam,GetSheetOkButtonText());
	return(0);
}

LONG CPropertySheetDialog::OnEnableSheetButtons(UINT /*wParam*/,LONG lParam)
{
	EnableSheetButtons((const char*)lParam);
	return(0);
}

LONG CPropertySheetDialog::OnDisableSheetButtons(UINT /*wParam*/,LONG lParam)
{
	DisableSheetButtons((const char*)lParam);
	return(0);
}

LONG CPropertySheetDialog::OnPropertySheetButton(UINT wParam,LONG lParam)
{
	int message = (int)wParam;
	LPSTR prompt = (LPSTR)lParam;
	CWnd* pIDOk = this->GetDlgItem(IDOK);
	CWnd* pIDCancel = this->GetDlgItem(IDCANCEL);

	switch(message)
	{
		case WM_SETPROPERTYSHEET_IDOKBUTTON:
			if(pIDOk)
				pIDOk->SetWindowText(prompt);
			break;
		case WM_GETPROPERTYSHEET_IDOKBUTTON:
			if(pIDOk)
				pIDOk->GetWindowText(prompt,MAX_BUTTON_PROMPT);
			break;
		case WM_SETPROPERTYSHEET_IDCANCELBUTTON:
			if(pIDCancel)
				pIDCancel->SetWindowText(prompt);
			break;
		case WM_GETPROPERTYSHEET_IDCANCELBUTTON:
			if(pIDCancel)
				pIDCancel->GetWindowText(prompt,MAX_BUTTON_PROMPT);
			break;
		case WM_ENABLEPROPERTYSHEET_IDOKBUTTON:
			if(pIDOk)
				pIDOk->EnableWindow(TRUE);
			break;
		case WM_DISABLEPROPERTYSHEET_IDOKBUTTON:
			if(pIDOk)
				pIDOk->EnableWindow(FALSE);
			break;
		case WM_ENABLEPROPERTYSHEET_IDCANCELBUTTON:
			if(pIDCancel)
				pIDCancel->EnableWindow(TRUE);
			break;
		case WM_DISABLEPROPERTYSHEET_IDCANCELBUTTON:
			if(pIDCancel)
				pIDCancel->EnableWindow(FALSE);
			break;
	}

	return(0);
}

/*
	EnableSheetButton()
*/
void CPropertySheetDialog::EnableSheetButton(UINT id)
{
	CWnd* pWnd;

	if((pWnd = GetDlgItem(id))!=NULL)
		pWnd->EnableWindow(TRUE);
}

/*
	DisableSheetButton()
*/
void CPropertySheetDialog::DisableSheetButton(UINT id)
{
	CWnd* pWnd;

	if((pWnd = GetDlgItem(id))!=NULL)
		pWnd->EnableWindow(FALSE);
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Italy Italy
I like C and C++, Acid Jazz, James Brown, gli Spaghetti Aglio e Olio, alla Bolognesa, alla Puttanesca e le Fettuccine alla Matriciana ('Maccaroni' over the world). Of course I like beautiful big tits girls too, my little car, Frank Zappa, the art of Zen, italian coffee and much more...

Comments and Discussions