您的位置:首页 > 理论基础 > 计算机网络

网络扫描技术揭秘读书笔记2--扫描器中公用编程示例(1)

2013-10-30 21:31 218 查看
编程环境:工具  VS2010  MFC  使用字符集:Unicode 

1.     
CTreeCtrl控件的应用




在对话框中,放置一个CTreeCtrl树型控件,属性Has Buttons、HasLines和Lines At Root都设为True,调整到合适的位置和大小,同时要声明一个CTreeCtrl的变量与此控件绑定:

CTreeCtrlm_ctlTreeResult;

在VC++里,所有的节点都是一个HTREEITEM的数据结构。

生成树状结构,只需要用到一个主要的函数InsertItem即可,该函数有如下几种调用方式:

HTREEITEMInsertItem( LPTVINSERTSTRUCT lpInsertStruct );

HTREEITEMInsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINTnState, UINT nStateMask, LPARAM lParam, HTREEITEM hParent, HTREEITEMhInsertAfter );

HTREEITEMInsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEMhInsertAfter = TVI_LAST );

HTREEITEMInsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent= TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);

返回值:无论哪一个调用,如果调用成功返回的都是一个HTREEITEM变量(该变量实际就是一个句柄);如果调用失败,返回的是一个NULL。在平时使用中,如果要插入的项是叶子节点,可以不考虑返回值,如果是根节点或分支节点,则需要保存返回的值,因为下一步在该节点下面再加入新的节点时,要用到这个返回值。

在第3项调用中,参数lpszItem即插入节点的描述字符串。hParent表示将当前哪个节点作为父节点,插入到该节点下面,默认的值是TVI_ROOT,表示直接插入到根节点下,否则就可以用前面调用InsertItem之后保存的返回值作为父节点,将当前节点插入到该节点的下面。hInsertAfter表示当要插入的父节点已有子节点时,当前插入的节点放置到什么位置,可取值分别为:



BOOL CCTreeCtrlEGDlg::OnInitDialog()
{
CString strItem;//用于生成各项的值。
strItem.Format(_T("NetBIOS扫描[127.0.0.1]"));
//将根节点插入,并记下该节点的位置到root变量中,以备后面再插入节点时使用
HTREEITEM root=m_ctlTreeResult.InsertItem(strItem);

strItem.Format(_T("主机名:localhost"));
//插入“主机名”的叶子节点到root根节点上
m_ctlTreeResult.InsertItem(strItem,root);

strItem.Format(_T("共享文件夹"));
//插入“共享文件夹”的分支节点到root根节点上
HTREEITEM curr=m_ctlTreeResult.InsertItem(strItem,root); //插入在root根节点下

int iItemDir=3;
char *ShareFolers[3]={"E$[]","IPC$[]","D$[]"};
TCHAR *TcharTempItem;
int i,byteLen,Charlen;
for (i=0;i<iItemDir;i++)
{ //依次生成各个共享的文件夹名
//char *-->CString(TCHAR)
byteLen=strlen(ShareFolers[i]);
//1.先计算多字节字符的大小
Charlen=MultiByteToWideChar(CP_ACP,0,ShareFolers[i],byteLen,NULL,0);
//2.为宽字节字符数组申请空间
TcharTempItem=new TCHAR[Charlen+1];
//3.多字节编码转换成宽字节编码(In Unicode: TCHAR/CString)
MultiByteToWideChar(CP_ACP,0,ShareFolers[i],byteLen,TcharTempItem,Charlen);
TcharTempItem[Charlen]='\0';//添加字符串结尾标示符
m_ctlTreeResult.InsertItem(TcharTempItem,curr);  //插入在curr结点下作为子节点
}

strItem.Format(_T("当前时间:2013-10-27"));//当前时间
//插入“当前时间”的叶子节点到root根节点上
m_ctlTreeResult.InsertItem(strItem,root);

strItem.Format(_T("用户名"));
//插入“用户名”的分支节点到root根节点上
curr=m_ctlTreeResult.InsertItem(strItem,root);
char *Users[3]={"Wang","Zhou","Li"};
for (i=0;i<iItemDir;i++)
{
byteLen=strlen(Users[i]);
Charlen=MultiByteToWideChar(CP_ACP,0,Users[i],byteLen,NULL,0);
TcharTempItem=new TCHAR[Charlen+1];
MultiByteToWideChar(CP_ACP,0,Users[i],byteLen,TcharTempItem,Charlen);
TcharTempItem[Charlen]='\0';
m_ctlTreeResult.InsertItem(TcharTempItem,curr);
}
}


运行结果:



2.   CListCtrl控件的应用



要创建这样的一个结构,首先需要在对话框中,放置一个CListCtrl列表控件,调整到合适的位置和大小,同时要声明一个CListCtrl的变量与此控件绑定。

注意不要忘了将View属性设为Report,即为报表风格

CListCtrlm_ctlListResult;

与树型控件CTreeCtrl不同的是,CListCtrl的创建要分两步,第一步是设置控件的表头部分,第二步才是增、修、删其数据项。

/*预定义一些字段顺序的宏定义,之后如果想调整字段的顺序,只需要修改此宏定义的
顺序即可。注意:下面宏定义由0起,并且顺序号必须相连,不得间断。*/
#define LIST_RESULT_INDEX       0
#define LIST_RESULT_IP          1
#define LIST_RESULT_STATUS      2
#define LIST_RESULT_MAC         3
#define LIST_RESULT_NAME        4
#define LIST_RESULT_COMMENT     5

BOOL ScanListDlg::OnInitDialog()
{
CoInitialize(NULL); //初始化COM库

CDialogEx::OnInitDialog();//必须先初始化对话框
CRect rect;
// 获取列表视图控件的位置和大小
m_ctlListResult.GetClientRect(&rect);
//设定列表的风格是有网格线,并且在选择的时候是选中一行,而不是首字段
m_ctlListResult.SetExtendedStyle(m_ctlListResult.GetExtendedStyle()|LVS_EX_FULLROWSELECT| LVS_EX_GRIDLINES);
//创建表头部分
//m_ctlListResult.InsertColumn(LIST_RESULT_INDEX,_T("序号"),LVCFMT_CENTER,rect.Width()/6,0);
m_ctlListResult.InsertColumn(LIST_RESULT_INDEX,_T("序号"),LVCFMT_CENTER,40);
m_ctlListResult.InsertColumn(LIST_RESULT_IP,_T("IP"),LVCFMT_LEFT,110);
m_ctlListResult.InsertColumn(LIST_RESULT_STATUS,_T("状态"),LVCFMT_LEFT,80);
m_ctlListResult.InsertColumn(LIST_RESULT_MAC,_T("MAC"),LVCFMT_LEFT,115);
m_ctlListResult.InsertColumn(LIST_RESULT_NAME,_T("主机名"),LVCFMT_LEFT,100);
m_ctlListResult.InsertColumn(LIST_RESULT_COMMENT,_T("注释"),LVCFMT_LEFT,100);
CString strItem;//用于生成各项的值
int iNum=10;
for (int i=0;i<iNum;i++)
{
strItem.Format(_T("%d"),i+1);
m_ctlListResult.InsertItem(i,strItem); //插入列表项(即每行第一个元素)
strItem.Format(_T("192.168.1.%d"),i+1);
//设置列表子项文本
m_ctlListResult.SetItemText(i,LIST_RESULT_IP,strItem);
m_ctlListResult.SetItemText(i,LIST_RESULT_STATUS,_T("扫描中..."));
m_ctlListResult.SetItemText(i,LIST_RESULT_MAC,_T("FF-FF-FF-FF-FF-FF"));
m_ctlListResult.SetItemText(i,LIST_RESULT_NAME,_T("localhost"));
m_ctlListResult.SetItemText(i,LIST_RESULT_COMMENT,_T("No"));
}
return TRUE;
}


运行结果:



3.IP地址互换

一个IP地址通常描述为以点分隔的字符串,例如“192.168.1.100”,这种方式很方便于人识别,但在计算机处理中并不方便,原因在于这样表示的IP地址存在以下不足:(1)整个字符串的长度不定长,给传输、存储带来麻烦。(2)给编程时的程序判断带来麻烦,例如想知道某一个IP之后的一个IP是什么,再如某一个IP是不是在某两个IP所组成的IP网段里?

计算机所处理的IP地址是用一种UINT无符号整型表示的(当然,在使用中用int或DWORD也都可以),这样做可以避免字符串表示方式中难以处理的问题,但却具有可读性差的缺点,因此一个程序中,应该同时具有两种表现形式,又可以相互转换。

要实现其中几种类型的转换,可以使用系统提供的API函数,也可以自己编写。使用API的优点是直接使用,缺点是不够灵活,有些API当输入出错时,会自动按默认数据处理,而自己编写的转换函数可以按自己要求处理。

1.Win32 Console版

char *iptos(UINT in)
{
char *output=new char[16];
u_char *p=(u_char *)in;
sprintf(output, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return output;
}

UINT StringIptoUint(const char *IpString)//Convert IP Address(String Format to Long)
{//eg:172.22.145.128
UINT IpUint=0;
char *temp=new char[4];
int i,t=1;
int dot_len=0;
memset(temp,0,4);
for(i=0;i<(int)strlen(IpString);i++)
{ /*   >>> 172+22*256+145*256*256+128*256*256*256    */
if(IpString[i]=='.')
{
memcpy(temp,IpString+i-dot_len,dot_len);
IpUint+=StringNumToUint(temp)*t;//*********
t*=256;
memset(temp,0,sizeof(temp));
dot_len=0;
}
else
dot_len++;
}
//最后一个点分十进制  即UINT的最高字节
memcpy(temp,IpString+i-dot_len,dot_len);
IpUint+=StringNumToUint(temp)*t;
printf("IpUint=%u\n",IpUint);
return IpUint;
}


2.MFC版

typedef union MultiByteStruct
{//IP地址联合体
int iInt;   //int有符号整型
float fFloat;   //浮点数
UINT uInt;  //无符号整数
ULONG uLong;    //ULONG无符号整型
DWORD dwDword;  //DWORD有符号整型
WORD wWord[2];  //WORD无符号整型数组
UCHAR ucByte[4];    //无符号字符数组
char cByte[4];  //字符数组
}UNIONIP,*PUNIONIP;

CString IPConvert::IPIntToStr(UINT IPInt)
{
CString IPStr;
UNIONIP IP;
IP.uInt=IPInt;
IPStr.Format(_T("%d.%d.%d.%d"),IP.ucByte[0],IP.ucByte[1],IP.ucByte[2],IP.ucByte[3]);
return IPStr;
}

UINT IPConvert::IPStrToInt(CString IPStr,BOOL bShowMsgBox)
{
UNIONIP IP;
int i,j=0;
IPStr.TrimLeft(_T(" "));
IPStr.TrimRight(_T(" "));
for (i=0;i<IPStr.GetLength();i++)
{
if (IPStr.GetAt(i) <'0' || IPStr.GetAt(i)>'9')
if (IPStr.GetAt(i) == '.')
j++;
else
{
if (bShowMsgBox)
MessageBox(_T("IP串中有非法字符,合适的字符为“0~9”和“.”!"));
return 0;
}
}
if (j!=3)
{
if (bShowMsgBox)
MessageBox(_T("IP串格式不对!"));
return 0;
}
i=0;
IPStr+=".";
CString temp;
char *charstr_temp;//
for (int m=0;m<4;m++)
{
temp="";
while (IPStr.GetAt(i) != '.')
{
temp+=IPStr.GetAt(i);
i++;
}
i++;
CStringToCharStr(temp,&charstr_temp);
if (temp=="" || atoi(charstr_temp) > 0xFF)
{
if (bShowMsgBox)
MessageBox(_T("IP串格式不对!"));
return 0;
}
else
{
CStringToCharStr(temp,&charstr_temp);
IP.ucByte[m]=atoi(charstr_temp);
}
}

return IP.uInt;
}

void IPConvert::CStringToCharStr(CString str,char **char_str)
{
int charlen=str.GetLength();//字符长度
int Bytelen = WideCharToMultiByte(CP_ACP,0,str,charlen,NULL,0,NULL,NULL);//字节长度
*char_str = new char[Bytelen+1];  //以字节为单位
WideCharToMultiByte(CP_ACP,0,str,charlen,*char_str,Bytelen,NULL,NULL);
(*char_str)[Bytelen] = '\0'; //多字节字符以'\0'停止
}

4.Windows操作系统类型的判断

通过GetVersion和GetVersionEx函数读取操作系统的版本 

该函数返回一个DWORD类型,其中数据高位是主版本号,数据低位是次版本号。

#ifndef _GETOSTYPE_H_
#define _GETOSTYPE_H_

enum Win32Type{Win32s,WinNT3,Win95,Win98,WinME,WinNT4,Win2000,WinXP,Win7};

Win32Type IsShellType();

static Win32Type g_Shell=IsShellType();

Win32Type IsShellType()
{
Win32Type  ShellType;
DWORD winVer;
OSVERSIONINFO *osvi;
//通过GetVersion和GetVersionEx函数读取操作系统的版本
//该函数返回一个DWORD类型,其中数据高位是主版本号,数据低位是次版本号。
winVer=GetVersion();
if(winVer<0x80000000)//最高位
{/*NT架构系列*/
ShellType=WinNT3;
osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
if (osvi!=NULL)
{
memset(osvi,0,sizeof(OSVERSIONINFO));
osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
GetVersionEx(osvi);
//主版本等于4,表示是Windows NT4.0系列
if(osvi->dwMajorVersion==4L)
ShellType=WinNT4;
//主版本等于5,次版本是0,表示是Windows 2000系列
else if(osvi->dwMajorVersion==5L && osvi->dwMinorVersion==0L)
ShellType=Win2000;
//主版本等于5,次版本是1,表示是Windows XP系列
else if(osvi->dwMajorVersion==5L && osvi->dwMinorVersion==1L)
ShellType=WinXP;
//Windows NT6.1  --Windows 7
else if(osvi->dwMajorVersion==5L && osvi->dwMinorVersion==1L)
ShellType=Win7;
free(osvi);
}
}
else
{
if  (LOBYTE(LOWORD(winVer))<4)
ShellType=Win32s;
else
{
ShellType=Win95;
osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
if (osvi!=NULL)
{
memset(osvi,0,sizeof(OSVERSIONINFO));
osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
GetVersionEx(osvi);
//主版本等于4,次版本是10,表示是Windows 98系列
//主版本等于4,次版本是90,表示是Windows ME系列
if(osvi->dwMajorVersion==4L && osvi->dwMinorVersion==10L)
ShellType=Win98;
else
{
if(osvi->dwMajorVersion==4L && osvi->dwMinorVersion==90L)
ShellType=WinME;
}
free(osvi);
}
}
}
return ShellType;
}
#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络扫描