MFC界面编程: 为 Arp协议获得本地局域网内在线主机MAC地址的程序 编写 界面

来源:互联网 发布:python有什么用 编辑:程序博客网 时间:2024/05/17 08:53

Section I Problem Specification

本次实验是用C/C++是在上一次实验:使用Arp协议获得本地局域网内在线主机MAC地址的基础上,进行一次的扩展。主要是做一个界面,并且因为要做界面多出了一个多线程的问题。出现多线程的原因是:必须有一个线程用于处理界面的事件。如此一说,反而像是我们在原来的基础上多做了一个线程,然后让这个线程去处理界面的事件,但实际情况不是这样。这是因为我在制作这种基于windows窗体程序的时候,基于了一个框架——MFC。这个框架可以理解为:微软专门为方便开发windows窗体程序的而设计的程序。在我以往的经验中,遇见了google专门为方便开发android应用而设计的程序,那时我管它叫sdk:Software Development Kit, 即软件开发工具包。

在这个框架下开发windows应用,无疑是非常方便的,但是我们也必须遵循这个框架已有的规矩:主线程就是控制界面的线程,这一点与我前面所说的多一个线程来控制界面相反。是在本来就有的界面线程的基础上,我创建了一个新的线程:来发包和收报在这次编写windows的程序过,我遇见了很多与开发android应用一样的准则。比如说:只要主线程才能更新界面,所以,当工作线程想要更新界面,也只有委托主线程。又比如:可以采用拖拉的方式来对界面进行布局,直观而又快速。

固,此次实验的重点是

1.制作界面。

2.多线程的应用。

3.与已有代码的融合。

 

Section II Solution Method and Design

对于界面的制作:

先利用MFC建立一个基于对话框的程序。当如此选择确定之后,MFC已经为我们生成了许多的内容。主要是对话框这个类以及初始化对话框的一些代码。此时,我们可以直接编译,会运行出现一个对话框。我们可以在资源视图内选择该对话框,再在工具箱内找到许多控件,这些控件包括:按钮,checkbox,listbox等等。我们可以直接拖动将其放置在对话框内。此时有4个要点:

1.       双击控件,可以直接调转到该控件的监听事件,比如:双击按钮控件就跳转到一个函数,当该按钮被点击时,该函数就会执行。我在android开发的时候,称为给button增加监听和响应函数。

 

2.       右键点击控件,在出来的弹窗内选择“添加变量”,这是指给这个控件命名。此外,该控件是属于对话框这个类的一个属性。我们也可以利用对话框的实例的引用调用它。

 

3.       右键点击控件,在出来的弹窗内选择“类向导”,我们可以在这里面添加额外的消息事件,比如双击按钮时响应的函数。这里面也比较统揽全局查看所有控件的所有能产生消息的事件。

 

4.      Cdialog1Dlg::OnInitDialog()是当对话框刚产生的时候会执行的函数,可以将其作为这个程序的起点,一些初始化的内容可以写在里面。

 

 

对于多线程的制作

对我来说难度不大。也就是调用这个框架下的MFC而已,主要是以下几个函数:

1.创建一个线程

HANDLE m_hThread =CreateThread(NULL, 0, ThreadProcGetMacByWinpcap, this, 0, NULL);

其中重要的参数有:

ThreadProcGetMacByWinpcap:这是一个函数,就是线程开时候要执行的函数

This:this代表实例,由于我们有这个代码是写在对话框的这个类的实现函数里面,这个this就代表了目前我们这个对话框的实例(这个对象)。

2.暂停线程的运行:SuspendThread(m_hThread)

3.恢复线程的运行:ResumeThread(m_hThread)

4.停止线程:             TerminateThread(m_hThread,0)

 

 

在适当的消息函数内使用上述几个api,就可以比较好的控制另一个线程。虽然控制线程的方法有很多,但是我在本试验中只用到了那么几个。本次实验,我也就只用到了2个线程。一个是主线程,一个就是发包和收包的线程。书上写的用了3个线程,我实在是看不出用三个线程的必要性。如下图所示:

关于与自己的代码融合:

我觉得也就是处理一堆逻辑,没有什么值得叙述的。本次实验本来应该难点,求出本网段所有在线主机的mac地址:处理方法也就是连续发253个就行了。

 

Section III Test Cases and Results Analysis

获取用户名非常耗时,所以分两种情况:

1.       不获得用户名,一般在1秒之内即可。

2.   获取用户名的,每次去获得一次用户名需要耗时4秒左右。

Section IV Conclusion

1.觉得iphelper用起来方便,所以用iphelper来获取了IP地址,子网掩码,本机mac地址,网关。发包和收包我还是用winpcap。

 

2.网关的mac地址使用了GetIpNetTable2的方法:http://msdn.microsoft.com/en-us/library/windows/desktop/aa814420(v=vs.85).aspx

 

3.我始终没有能够用winpcap拿到正确的ip。进而拿不到对子网掩码。这部分我打算打linux系统下验证,到底怎么回事

//sockaddr_in*sin=(sockaddr_in*)&(Dev->addresses->addr);

//MessageBox(inet_ntoa(sin->sin_addr));

 

4.关键是不能用iphelper的方法来拿到发arp。必须用winpcap来发。winpcap里面必须要选择一个打开的设备。这一步我又跳不过,但是最终还是找到了办法。因为pcap_open得第一参数需要dev的name,仔细观察这一部分,发现和用iphelper得到的pAdapter->AdapterName。后面的一段字符是一样的。 将这后面一段一样的比较一部分,就知道打开的是哪个设备了。

代码中的321行起。虽然有点二,但是我还是很找办法啦!!

 

5.由于用winpcap的方法不能获得在线主机的主机名字。需要调用gethostbyaddr的方法。但是这个方法非常花时间。所以我又添加了一个checkbox,以确定是否显示主机名字,如果不显示就会非常的快.为什么这么慢?

 

6.我们目前写个程序的流程。无非就是:

首先,明确自己要做什么,想要什么。

其次,怎么要,就是调哪个api。接着,就是 了解api的参数,包括返回值之类的。

最后,处理一下逻辑就可以了。

 

7.关于工作线程不能更新界面的问题:

根据我以往的经验:如在android应用,工作线程想要更新界面,必须发一个消息(handler机制)给主线程,让主线程执行更新的代码。

虽然windows也有这样的机制,但是我却没有使用。

我直接使用了如下:即可直接更新界面了。

这是为什么?这种方法从VC++从入门到精通的书中学到。

m_hThread =CreateThread(NULL,0,ThreadProcGetMacByWinpcap,this,0,NULL);

 

DWORD_stdcall ThreadProcGetMacByWinpcap(LPVOID lpParameter){

 

Cdialog->m_listbox.AddString(str);

 

}

 

8.其实很多我觉得搞得我头痛的地方也就是 api不熟悉,c++不熟悉,框架不熟悉。

 

 

最重要是的:感受到软件设计的重要性。这次,我没有提前调查充分,就盲目开始写代码。包括试图参考博客,就想把写出windows界面,结果博客是东一下西一下,不基础和不系统,我浪费了整整两天的时间。最后我看了一个vc++从入门到精通的书,一下就霍然开朗了。其实我需要的也就最基础的不超不过10页的内容。所以,开始之前要调查好技术,自己这个技术熟悉不熟悉,不熟悉就要放低姿态从入门开始。另外就是,我一开始上来就编码,就写代码,写一点查一点资料。winpcap获得不了主机名,我还在用它,结果写完了发现不符合要求了。又改用sendarp,浪费时间(后来用sendarp的线程快写好,才发现不是sendarp,是gethostbyaddr)。所以,首先要熟悉好需求,以需求为导向,大略的写一下设计文档。我相信这才是一个正确的开发流程。总之,不要盲目编码,一定要调查好。

 

5和7需要解答。

 

Section V References

计算机网络高级软件编程技术

第三章 使用ARP协议获取局域网内活动主机的物理地址

 

大量查询msdn,例如下列网址:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa814420(v=vs.85).aspx

 

Visual C++从入门到精通

 

Section VI Appendix

新建一个以对话框为基础的工程,我的代码主要写在了dialog1Dlg.cpp这个文件里。想对应的:dialog1Dlg.h也有一些变化,主要就是声明一些变量和方法。

由于对某个按钮的监听是在通过一个界面来双击完成的,而我记不得按钮的添加顺序还有listbox的添加顺序,所以下面的代码的监听不一定能清晰的指出是哪个按钮或者listbox的监听。

再添一幅图,表明 “界面布局 ,添加buttond ”的地方在哪里。那个IDD_DIALOG1_DIALOG有点像id号。保证唯一的识别性:比如这个IDD_DIALOG1_DIALOG就是dialog1Dlg.h 这个类的界面布局。




dialog1Dlg.cpp的代码如下:

#ifndef WIN32_LEAN_AND_MEAN#define WIN32_LEAN_AND_MEAN#endif#include "stdafx.h"#include "dialog1.h"#include "dialog1Dlg.h"#include "afxdialogex.h"#include "winsock2.h" #include "iphlpapi.h"  #include "pcap.h" #include <windows.h>#include <ws2ipdef.h>#include <stdio.h>#include <stdlib.h>#pragma comment(lib,"Ws2_32.lib")#pragma comment(lib, "Iphlpapi.lib")#pragma comment(lib, "wpcap.lib ")#ifdef _DEBUG#define new DEBUG_NEW#endif#define WM_MYUPDATEDATA WM_USER+100  pcap_if_t* Dev,*allDevs; pcap_t* currentOpenDev;CString str;PIP_ADAPTER_INFO pAdapter = 0;  PIP_ADAPTER_INFO currentSlectedAdapter = 0;  ULONG uBuf = 0;  DWORD dwRet;typedef struct Frame{unsigned char destinationAddress[6];//疑问:原来我填的本机mac地址无论是无线的还是有线的。只要是本机的就行。为什么unsigned char sourceAddress[6];unsigned short ethernetType;unsigned short hardwareType;unsigned short protocalType;unsigned char hardwareSize;unsigned char protocalSIze;unsigned short Opcode;unsigned char senderHardwareAddress[6];unsigned char senderIP[4];//不用填也可以。unsigned char targetHardwareAddress[6];unsigned char targetIP[4];};// 用于应用程序“关于”菜单项的 CAboutDlg 对话框class CAboutDlg : public CDialogEx{public:CAboutDlg();// 对话框数据enum { IDD = IDD_ABOUTBOX };protected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持// 实现protected:DECLARE_MESSAGE_MAP() LRESULT OnUpdateMyData(WPARAM wParam, LPARAM lParam);  };CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD){}void CAboutDlg::DoDataExchange(CDataExchange* pDX){CDialogEx::DoDataExchange(pDX);}BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)END_MESSAGE_MAP()// Cdialog1Dlg 对话框Cdialog1Dlg::Cdialog1Dlg(CWnd* pParent /*=NULL*/): CDialogEx(Cdialog1Dlg::IDD, pParent){m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void Cdialog1Dlg::DoDataExchange(CDataExchange* pDX){CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_LIST1, m_ListBox);DDX_Control(pDX, IDC_LIST3, m_ComboxResults);DDX_Control(pDX, IDC_LIST4, m_ListBoxIpAddress);DDX_Control(pDX, IDC_LIST5, m_ListBoxSubnetMask);DDX_Control(pDX, IDC_LIST7, m_ListBoxMacAddress);DDX_Control(pDX, IDC_LIST6, m_ListBoxGateWayIp);DDX_Control(pDX, IDC_LIST8, m_ListBoxGateWayMac);DDX_Control(pDX, IDOK, m_scanButton);DDX_Control(pDX, IDOK2, m_stopscanning);DDX_Control(pDX, IDC_CHECK3, m_showHostName);}BEGIN_MESSAGE_MAP(Cdialog1Dlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDOK, &Cdialog1Dlg::OnBnClickedOk)ON_LBN_SELCHANGE(IDC_LIST1, &Cdialog1Dlg::OnLbnSelchangeList1)ON_LBN_SELCHANGE(IDC_LIST3, &Cdialog1Dlg::OnLbnSelchangeList3)ON_LBN_SELCHANGE(IDC_LIST7, &Cdialog1Dlg::OnLbnSelchangeList7)ON_LBN_SELCHANGE(IDC_LIST8, &Cdialog1Dlg::OnLbnSelchangeList8)ON_BN_CLICKED(IDOK2, &Cdialog1Dlg::OnBnClickedOk2)ON_BN_CLICKED(IDC_CHECK3, &Cdialog1Dlg::OnBnClickedCheck3)END_MESSAGE_MAP()// Cdialog1Dlg 消息处理程序BOOL Cdialog1Dlg::OnInitDialog(){CDialogEx::OnInitDialog();// 将“关于...”菜单项添加到系统菜单中。// IDM_ABOUTBOX 必须在系统命令范围内。ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){BOOL bNameValid;CString strAboutMenu;bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动//  执行此操作SetIcon(m_hIcon, TRUE);// 设置大图标SetIcon(m_hIcon, FALSE);// 设置小图标// TODO: 在此添加额外的初始化代码dwRet = GetAdaptersInfo(pAdapter,&uBuf); if(dwRet == ERROR_BUFFER_OVERFLOW)  {  pAdapter = (PIP_ADAPTER_INFO)GlobalAlloc(GPTR,uBuf);  dwRet = GetAdaptersInfo(pAdapter,&uBuf);if (dwRet == ERROR_SUCCESS)  {m_ListBox.AddString(pAdapter->Description);m_ListBox.AddString(pAdapter->Next->Description);}}m_stopscanning.EnableWindow(FALSE);m_hThread=NULL;return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE}void Cdialog1Dlg::OnSysCommand(UINT nID, LPARAM lParam){if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialogEx::OnSysCommand(nID, lParam);}}// 如果向对话框添加最小化按钮,则需要下面的代码//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,//  这将由框架自动完成。void Cdialog1Dlg::OnPaint(){if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();}}//当用户拖动最小化窗口时系统调用此函数取得光标//显示。HCURSOR Cdialog1Dlg::OnQueryDragIcon(){return static_cast<HCURSOR>(m_hIcon);}/*//使用iphelper的sendarp来获得mac地址和主机名。DWORD _stdcall ThreadProcGetMacByIphelper(LPVOID lpParameter){Cdialog1Dlg *Cdialog=(Cdialog1Dlg*)lpParameter;WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested = MAKEWORD( 2, 2 );err = WSAStartup( wVersionRequested, &wsaData );if ( err != 0 ) {return -1;}HRESULT hr;ULONG   pulMac[2];ULONG   ulLen;in_addr beginaddr, endaddr;   //unsigned long be, en;char badd[16]={0};   char eadd[16]={0};char add[16]={0};char name[30]={0};hostent *pht=NULL;CString a;Cdialog->m_ListBoxIpAddress.GetText(0,a);CString sub = a.Mid(0, a.ReverseFind('.'));//这个sub是去掉了ip最后的“.xxx”的方式。beginaddr.S_un.S_addr = inet_addr(sub+".1");endaddr.S_un.S_addr = inet_addr(sub+".255");Cdialog->MessageBox(sub+".255");be = ntohl(beginaddr.S_un.S_addr);en = ntohl(endaddr.S_un.S_addr);while(be<=en){ulLen = 6;//调用了//第一个参数是IP地址的网络字节顺序//第二个参数填0就可以//第三个参数是MAC缓冲区指针//第四个参数是一个指向一个DWORD型数值为6的指针hr = SendARP(beginaddr.S_un.S_addr, 0, pulMac, &ulLen);if(hr == NO_ERROR){memcpy(add,inet_ntoa(beginaddr),16);pht = gethostbyaddr((char*)&beginaddr, sizeof(beginaddr), AF_INET);if (pht != NULL){size_t i, j;char * szMac = new char[ulLen*3];PBYTE pbHexMac = (PBYTE) pulMac;for (i = 0, j = 0; i < ulLen - 1; ++i) {j += sprintf (szMac + j, "%02X:", pbHexMac[i]);}sprintf (szMac + j, "%02X", pbHexMac[i]);memcpy(name, pht->h_name, 30);   printf("%-18s %-20s %-20sis online./n", add, name, szMac);delete [] szMac;}be++;beginaddr.S_un.S_addr = htonl(be);}else{be++;beginaddr.S_un.S_addr = htonl(be);continue;}}WSACleanup( );system("pause");}*///这个方法是使用winpcap来获得ip和mac,但是却获得不了主机名,这样就不符合老师的要求//所以重新写一个线程。还可以获得主机名的那种。DWORD _stdcall ThreadProcGetMacByWinpcap(LPVOID lpParameter){Cdialog1Dlg *Cdialog=(Cdialog1Dlg*)lpParameter;char errBuf[PCAP_ERRBUF_SIZE]; //存放错误信息的缓冲.下面那个pcap_findalldevs 函数用来存放错误信息。http://blog.chinaunix.net/uid-28698407-id-3843171.htmlpcap_findalldevs(&allDevs,errBuf);//列举所有设备 ,这里用来获取网络适配器信息的函数.pcap_findalldevs() returns 0 on success and -1 on failure.当errBuf满了会返回错误信息。CString a=currentSlectedAdapter->AdapterName;CString subfromIpHelper = a.Mid(a.ReverseFind('{')+1, 4);for(Dev=allDevs;Dev;Dev=Dev->next){a=Dev->name;CString subfromWinpcap = a.Mid(a.ReverseFind('{')+1, 4);if(subfromWinpcap==subfromIpHelper){break;}}if((currentOpenDev=pcap_open(Dev->name,65535,PCAP_OPENFLAG_PROMISCUOUS,1000,NULL,errBuf))==NULL)//打开设备 http://blog.sina.com.cn/s/blog_48fa680e010002xy.html{return 0;}int count;Frame senderFrame;for(count=0;count<6;count++){senderFrame.destinationAddress[count]=0xff;senderFrame.targetHardwareAddress[count]=00;}senderFrame.ethernetType=htons(0x0806);senderFrame.hardwareType=htons(0x0001);senderFrame.protocalType=htons(0x0800);senderFrame.hardwareSize=6;senderFrame.protocalSIze=4;senderFrame.Opcode=htons(0x0001);for (count=0;count<6;count++){senderFrame.sourceAddress[count]=currentSlectedAdapter->Address[count];senderFrame.senderHardwareAddress[count]=currentSlectedAdapter->Address[count];}unsigned char frame[60];long Time[256];Cdialog->m_ListBoxIpAddress.GetText(0,a);CString sub = a.Mid(0, a.ReverseFind('.'));//这个sub是去掉了ip最后的“.xxx”的方式。CString sub1=sub.Mid(0,3);CString sub2=sub.Mid(sub.Find('.')+1,sub.ReverseFind('.')-sub.Find('.')-1);CString sub3=sub.Mid(sub.ReverseFind('.')+1,3);str.Format("%c",sub1);senderFrame.targetIP[0]=atoi((LPCTSTR)sub1);senderFrame.targetIP[1]=atoi((LPCTSTR)sub2);senderFrame.targetIP[2]=atoi((LPCTSTR)sub3);for (senderFrame.targetIP[3]=1;senderFrame.targetIP[3]<255;senderFrame.targetIP[3]++){memset(&frame,0,sizeof(frame));memcpy(&frame,&senderFrame,sizeof(senderFrame));pcap_sendpacket(currentOpenDev,frame,sizeof(frame));Time[senderFrame.targetIP[3]]=GetTickCount();}int j=0;//其实只是一个用于超时的量。pcap_pkthdr* hdr; const u_char *pkt_datas;while(true){pcap_next_ex(currentOpenDev,&hdr,&pkt_datas); unsigned char *data=NULL;data=(unsigned char*)pkt_datas;unsigned char GetFrame[60];int i=0;for(i;i<60;i++){GetFrame[i]=*data;*data=*data+1;}if(data[12]==0x08&&data[13]==0x06&&data[20]==0x00&&data[21]==0x02){str.Format("%d.%d.%d.%d",data[28],data[29],data[30],data[31]);in_addr ipAddress;ipAddress.S_un.S_addr = inet_addr(str);hostent *pht=NULL;long elapsedTime=(GetTickCount()-Time[data[31]])/1000;if (Cdialog->m_showHostName.GetCheck()==BST_CHECKED){//1参数:指向网络字节顺序地址的指针。//2参数: 地址的长度,在AF_INET类型地址中为4。//3参数:地址类型,应为AF_INET。pht = gethostbyaddr((char*)&ipAddress, sizeof(ipAddress), AF_INET);if (pht!=NULL){if (elapsedTime==0){elapsedTime=1;str.Format("%d.%d.%d.%d\t\t%02X-%02X-%02X-%02X-%02X-%02X\t\t%15s\t\t<%lds",data[28],data[29],data[30],data[31],data[6],data[7],data[8],data[9],data[10],data[11],pht->h_name,elapsedTime);}str.Format("%d.%d.%d.%d\t\t%02X-%02X-%02X-%02X-%02X-%02X\t\t%15s\t\t%lds",data[28],data[29],data[30],data[31],data[6],data[7],data[8],data[9],data[10],data[11],pht->h_name,elapsedTime);}else{if (elapsedTime==0){elapsedTime=1;str.Format("%d.%d.%d.%d\t\t%02X-%02X-%02X-%02X-%02X-%02X\t\t%15s\t\t<%lds",data[28],data[29],data[30],data[31],data[6],data[7],data[8],data[9],data[10],data[11],"未能获得主机名",elapsedTime);}str.Format("%d.%d.%d.%d\t\t%02X-%02X-%02X-%02X-%02X-%02X\t\t%15s\t\t%lds\n",data[28],data[29],data[30],data[31],data[6],data[7],data[8],data[9],data[10],data[11],"未能获得主机名",elapsedTime);}}else{if (elapsedTime==0){elapsedTime=1;str.Format("%d.%d.%d.%d\t\t%02X-%02X-%02X-%02X-%02X-%02X\t\t%15s\t\t<%lds",data[28],data[29],data[30],data[31],data[6],data[7],data[8],data[9],data[10],data[11],"未能获得主机名",elapsedTime);}else{str.Format("%d.%d.%d.%d\t\t%02X-%02X-%02X-%02X-%02X-%02X\t\t%15s\t\t%lds\n",data[28],data[29],data[30],data[31],data[6],data[7],data[8],data[9],data[10],data[11],"未能获得主机名",elapsedTime);}}Cdialog->m_ComboxResults.AddString(str);//Cdialog->m_ComboxResults.Invalidate();//这句是刷新界面,但是不用也可以。true的话就是有刷新的效果,false就没有}}return 0;}void Cdialog1Dlg::OnBnClickedOk(){if(currentSlectedAdapter==0){MessageBox("请先于左侧框内选择设备!");}else{m_stopscanning.EnableWindow(TRUE);m_scanButton.EnableWindow(FALSE);if (m_hThread==NULL){m_hThread = CreateThread(NULL,0,ThreadProcGetMacByWinpcap,this,0,NULL);}else{ResumeThread(m_hThread);}}}void Cdialog1Dlg::OnLbnSelchangeList1(){CString selectedItem;m_ListBox.GetText(m_ListBox.GetCurSel(),selectedItem);currentSlectedAdapter=pAdapter;while (currentSlectedAdapter->Description!=selectedItem){currentSlectedAdapter=currentSlectedAdapter->Next;}inputLocalMacAddress();//输出并打印本地mac地址}void Cdialog1Dlg::OnLbnSelchangeList3(){// TODO: 在此添加控件通知处理程序代码}void Cdialog1Dlg::OnLbnSelchangeList7(){// TODO: 在此添加控件通知处理程序代码}void Cdialog1Dlg::OnLbnSelchangeList8(){// TODO: 在此添加控件通知处理程序代码}void Cdialog1Dlg::inputLocalMacAddress() {m_ListBoxMacAddress.ResetContent();//把内容清空m_ListBoxIpAddress.ResetContent();m_ListBoxSubnetMask.ResetContent();m_ListBoxGateWayIp.ResetContent();m_ListBoxGateWayMac.ResetContent();if (dwRet == ERROR_SUCCESS)  {m_ListBoxIpAddress.AddString(currentSlectedAdapter->IpAddressList.IpAddress.String);m_ListBoxSubnetMask.AddString(currentSlectedAdapter->IpAddressList.IpMask.String);m_ListBoxGateWayIp.AddString(currentSlectedAdapter->GatewayList.IpAddress.String);//重点:因为打印的是16进制的,所以必须这样转换。//我开始居然以为是将byte转换为Cstring打印出来。str.Format("%02x-%02x-%02x-%02x-%02x-%02x",currentSlectedAdapter->Address[0],currentSlectedAdapter->Address[1],currentSlectedAdapter->Address[2],currentSlectedAdapter->Address[3],currentSlectedAdapter->Address[4],currentSlectedAdapter->Address[5]);m_ListBoxMacAddress.AddString(str);//下面是获得gateway的网关的mac地址,是从本机的arp列表中获得的。int i;str="00-00-00-00-00";unsigned long status = 0;PMIB_IPNET_TABLE2 pipTable = NULL;//来自哪个头文件,请查询msdn//http://msdn.microsoft.com/en-us/library/windows/desktop/aa814420(v=vs.85).aspx status = GetIpNetTable2(AF_INET, &pipTable);for (i = 0; (unsigned) i < pipTable->NumEntries; i++){//下句是如果相等的话就会返回0,所以我再反一下。if(!(strcmp(inet_ntoa(pipTable->Table[i].Address.Ipv4.sin_addr),currentSlectedAdapter->GatewayList.IpAddress.String))){str.Format("%02x-%02x-%02x-%02x-%02x-%02x",pipTable->Table[i].PhysicalAddress[0],pipTable->Table[i].PhysicalAddress[1],pipTable->Table[i].PhysicalAddress[2],pipTable->Table[i].PhysicalAddress[3],pipTable->Table[i].PhysicalAddress[4],pipTable->Table[i].PhysicalAddress[5]);}}m_ListBoxGateWayMac.AddString(str);}}void Cdialog1Dlg::OnBnClickedOk2(){m_stopscanning.EnableWindow(FALSE);m_scanButton.EnableWindow(TRUE);SuspendThread(m_hThread);// TODO: 在此添加控件通知处理程序代码}void Cdialog1Dlg::OnBnClickedCheck3(){if(m_hThread!=NULL){TerminateThread(m_hThread,0);m_hThread=NULL;m_ComboxResults.ResetContent();}// TODO: 在此添加控件通知处理程序代码}

dialog1Dlg.h的代码如下:

// dialog1Dlg.h : 头文件//#pragma once#include "afxwin.h"// Cdialog1Dlg 对话框class Cdialog1Dlg : public CDialogEx{// 构造public:Cdialog1Dlg(CWnd* pParent = NULL);// 标准构造函数// 对话框数据enum { IDD = IDD_DIALOG1_DIALOG };protected:virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV 支持// 实现protected:HICON m_hIcon;// 生成的消息映射函数virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP()public:afx_msg void OnBnClickedOk();afx_msg void OnLbnSelchangeList1();CListBox m_ListBox;CListBox m_ComboxResults;afx_msg void OnLbnSelchangeList3();CListBox m_ListBoxIpAddress;CListBox m_ListBoxSubnetMask;afx_msg void OnLbnSelchangeList7();CListBox m_ListBoxMacAddress;CListBox m_ListBoxGateWayIp;afx_msg void OnLbnSelchangeList8();CListBox m_ListBoxGateWayMac;afx_msg void inputLocalMacAddress();CButton m_scanButton;afx_msg void OnBnClickedOk2();CButton m_stopscanning;HANDLE m_hThread;afx_msg void OnBnClickedCheck3();CButton m_showHostName;};

代码我已上传到云盘:搜索:PRJ03-20131017即可

原创粉丝点击