1.1.4 小试牛刀--编程实现获取MAC地址(1)
实例功能 使用Visual C++开发一个FTP传输系统
源码路径 光盘yuanma1FTP
本实例的目的是,使用Visual C++ 6.0开发一个获取当前机器MAC地址的程序。
1. 选择开发工具
Visual C++是一个功能强大的可视化软件开发工具。自1993年Microsoft公司推出Visual C++ 1.0以来,不断有其新版本问世,随后微软又推出了.NET系列,添加了很多网络功能,但是它的应用有一定的局限性。Visual C++已成为专业程序员进行软件开发的首选工具,其中,Visual C++ 6.0是其中比较成熟的一个版本,也是最常用的一个版本。
2. 设计MFC窗体
使用Visual C++ 6.0创建一个MFC项目后,根据本实例的需要,我们设计3个窗体,它们分别是IDD_ABOUTBOX(见图1-6)、IDD_GETNETSETTING_DIALOG(见图1-7)和IDD_CARDINFO(见图1-8)。
![]() |
图1-6 IDD_ABOUTBOX窗体 |
![]() |
图1-7 IDD_GETNETSETTING_DIALOG窗体 |
![]() |
图1-8 IDD_CARDINFO窗体 |
3. 具体编码
设计好窗体之后,接下来开始讲解具体的编码过程。
(1) 在文件ClassNetSetting.h中,定义类ClassNetSetting,根据不同的操作系统获取存储网卡的MAC地址的结构。具体代码如下:
- //操作系统类型
- enum Win32Type {
- Unknow,
- Win32s,
- Windows9X,
- WinNT3,
- WinNT4orHigher
- };
- typedef struct tagASTAT
- {
- ADAPTER_STATUS adapt;
- NAME_BUFFER NameBuff[30];
- } ASTAT, *LPASTAT;
- //存储网卡的MAC地址的结构
- typedef struct tagMAC_ADDRESS
- {
- BYTE b1,b2,b3,b4,b5,b6;
- } MAC_ADDRESS, *LPMAC_ADDRESS;
- //网卡信息的数据结构,包括记录网卡的厂商及型号,与之绑定的IP地址,网关,
- //DNS序列,子网掩码和物理地址
- typedef struct tagNET_CARD
- {
- TCHAR szDescription[256];
- BYTE szMacAddr[6];
- TCHAR szGateWay[128];
- TCHAR szIpAddress[128];
- TCHAR szIpMask[128];
- TCHAR szDNSNameServer[128];
- } NET_CARD, *LPNET_CARD;
- class ClassNetSetting
- {
- public:
- void ProcessMultiString(LPTSTR lpszString, DWORD dwSize);
- UCHAR GetAddressByIndex(int lana_num, ASTAT &Adapter);
- BOOL GetSettingOfWinNT();
- int GetMacAddress(LPMAC_ADDRESS pMacAddr);
- BOOL GetSetting();
- ClassNetSetting();
- virtual ~ClassNetSetting();
- public:
- BOOL GetSettingOfWin9X();
- Win32Type GetSystemType();
- int m_TotalNetCards; //系统的网卡数
- TCHAR m_szDomain[16]; //域名
- TCHAR m_szHostName[16]; //主机名
- int m_IPEnableRouter; //是否允许IP路由: 0-不允许, 1-允许, 2-未知
- int m_EnableDNS; //是否允许DNS解析: 0-不允许, 1-允许, 2-未知
- NET_CARD m_Cards[MAX_CARD]; //默认的最大网卡数是10
- Win32Type m_SystemType; //操作系统类型
- MAC_ADDRESS m_MacAddr[MAX_CARD]; //允许10个网卡
- };
(2) 编写文件ClassNetSetting.cpp,用于向网卡发送信息,以获取当前计算机的网卡数目和名称。具体代码如下:
- ClassNetSetting::ClassNetSetting()
- {
- m_TotalNetCards = 0;
- _tcscpy(m_szDomain,_T(""));
- _tcscpy(m_szHostName,_T(""));
- m_IPEnableRouter = 2;
- m_EnableDNS = 2;
- m_SystemType = Unknow;
- }
- ClassNetSetting::~ClassNetSetting()
- {
- }
- BOOL ClassNetSetting::GetSetting()
- {
- m_SystemType = GetSystemType();
- if (m_SystemType == Windows9X)
- return GetSettingOfWin9X();
- else if(m_SystemType == WinNT4orHigher)
- return GetSettingOfWinNT();
- else //不支持老旧的操作系统
- return FALSE;
- }
- Win32Type ClassNetSetting::GetSystemType()
- {
- Win32Type SystemType;
- DWORD winVer;
- OSVERSIONINFO *osvi;
- winVer = GetVersion();
- if(winVer < 0x80000000)
- {
- /*NT */
- SystemType = WinNT3;
- osvi = (OSVERSIONINFO*)malloc(sizeof(OSVERSIONINFO));
- if (osvi != NULL)
- {
- memset(osvi, 0, sizeof(OSVERSIONINFO));
- osvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(osvi);
- if (osvi->dwMajorVersion >= 4L)
- SystemType = WinNT4orHigher; //它是NT4或更高版本!
- free(osvi);
- }
- }
- else if (LOBYTE(LOWORD(winVer)) < 4)
- SystemType = Win32s; /*Win32s*/
- else
- SystemType = Windows9X; /*Windows9X*/
- return SystemType;
- }
- BOOL ClassNetSetting::GetSettingOfWin9X()
- {
- LONG lRet;
- HKEY hMainKey;
- TCHAR szNameServer[256];
- //得到域名,网关和DNS的设置
- lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- _T("System\CurrentControlSet\Services\VxD\MSTCP"),
- 0, KEY_READ, &hMainKey);
- if(lRet == ERROR_SUCCESS)
- {
- DWORD dwType, dwDataSize=256;
- ::RegQueryValueEx(hMainKey, _T("Domain"), NULL, &dwType,
- (LPBYTE)m_szDomain, &dwDataSize);
- dwDataSize = 256;
- ::RegQueryValueEx(hMainKey, _T("Hostname"), NULL, &dwType,
- (LPBYTE)m_szHostName, &dwDataSize);
- dwDataSize = 256;
- ::RegQueryValueEx(hMainKey, _T("EnableDNS"), NULL, &dwType,
- (LPBYTE)&m_EnableDNS, &dwDataSize);
- dwDataSize = 256;
- ::RegQueryValueEx(hMainKey, _T("NameServer"), NULL, &dwType,
- (LPBYTE)szNameServer, &dwDataSize);
- }
- ::RegCloseKey(hMainKey);
- HKEY hNetCard = NULL;
- //调用CTcpCfg类的静态函数得到网卡的数目和相应的MAC地址
- m_TotalNetCards = GetMacAddress(m_MacAddr);
- lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- _T("System\CurrentControlSet\Services\Class\Net"),
- 0, KEY_READ, &hNetCard);
- if(lRet != ERROR_SUCCESS) //此处失败就返回
- {
- if(hNetCard != NULL)
- ::RegCloseKey(hNetCard);
- return FALSE;
- }
- DWORD dwSubKeyNum = 0,dwSubKeyLen = 256;
- //得到子键的个数,通常与网卡个数相等
- lRet = ::RegQueryInfoKey(hNetCard, NULL, NULL, NULL,
- &dwSubKeyNum, &dwSubKeyLen, NULL,NULL,NULL,NULL,NULL,NULL);
- if(lRet == ERROR_SUCCESS)
- {
- //m_TotalNetCards = dwSubKeyNum; //网卡个数以此为主
- LPTSTR lpszKeyName = new TCHAR[dwSubKeyLen + 1];
- DWORD dwSize;
- for(int i=0; i<(int)m_TotalNetCards; i++)
- {
- TCHAR szNewKey[256];
- HKEY hNewKey;
- DWORD dwType=REG_SZ, dwDataSize=256;
- dwSize = dwSubKeyLen + 1;
- lRet = ::RegEnumKeyEx(hNetCard, i, lpszKeyName,
- &dwSize, NULL, NULL, NULL, NULL);
- if(lRet == ERROR_SUCCESS)
- {
- lRet = ::RegOpenKeyEx(hNetCard,
- lpszKeyName, 0, KEY_READ, &hNewKey);
- if(lRet == ERROR_SUCCESS)
- ::RegQueryValueEx(hNewKey, _T("DriverDesc"), NULL,
- &dwType, (LPBYTE)m_Cards[i].szDescription, &dwDataSize);
- ::RegCloseKey(hNewKey);
- wsprintf(szNewKey,
- _T("System\CurrentControlSet\Services\Class\NetTrans\%s"),
- lpszKeyName);
- lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- szNewKey, 0, KEY_READ, &hNewKey);
- if(lRet == ERROR_SUCCESS)
- {
- dwDataSize = 256;
- ::RegQueryValueEx(hNewKey, _T("DefaultGateway"), NULL,
- &dwType, (LPBYTE)m_Cards[i].szGateWay, &dwDataSize);
- ProcessMultiString(m_Cards[i].szGateWay, dwDataSize);
- dwDataSize = 256;
1.1.4 小试牛刀--编程实现获取MAC地址(3)
- ::RegQueryValueEx(hNewKey,_T("IPAddress"), NULL,
- &dwType, (LPBYTE)m_Cards[i].szIpAddress, &dwDataSize);
- ProcessMultiString(m_Cards[i].szIpAddress, dwDataSize);
- dwDataSize = 256;
- ::RegQueryValueEx(hNewKey, _T("IPMask"), NULL, &dwType,
- (LPBYTE)m_Cards[i].szIpMask, &dwDataSize);
- ProcessMultiString(m_Cards[i].szIpMask, dwDataSize);
- //拷贝前面得到的DNS主机名
- _tcscpy(m_Cards[i].szDNSNameServer, szNameServer);
- }
- ::RegCloseKey(hNewKey);
- }
- m_Cards[i].szMacAddr[0] = m_MacAddr[i].b1;
- m_Cards[i].szMacAddr[1] = m_MacAddr[i].b2;
- m_Cards[i].szMacAddr[2] = m_MacAddr[i].b3;
- m_Cards[i].szMacAddr[3] = m_MacAddr[i].b4;
- m_Cards[i].szMacAddr[4] = m_MacAddr[i].b5;
- m_Cards[i].szMacAddr[5] = m_MacAddr[i].b6;
- }
- }
- ::RegCloseKey(hNetCard);
- return lRet == ERROR_SUCCESS ? TRUE : FALSE;
- }
- int ClassNetSetting::GetMacAddress(LPMAC_ADDRESS pMacAddr)
- {
- NCB ncb;
- UCHAR uRetCode;
- int num = 0;
- LANA_ENUM lana_enum;
- memset(&ncb, 0, sizeof(ncb));
- ncb.ncb_command = NCBENUM;
- ncb.ncb_buffer = (unsigned char *)&lana_enum;
- ncb.ncb_length = sizeof(lana_enum);
- //向网卡发送NCBENUM命令,以获取当前机器的网卡信息,如有多少个网卡,
- //每张网卡的编号等
- uRetCode = Netbios(&ncb);
- if (uRetCode == 0)
- {
- num = lana_enum.length;
- //对每一张网卡,以其网卡编号为输入编号,获取其MAC地址
- for (int i=0; i<num; i++)
- {
- ASTAT Adapter;
- if(GetAddressByIndex(lana_enum.lana[i],Adapter) == 0)
- {
- pMacAddr[i].b1 = Adapter.adapt.adapter_address[0];
- pMacAddr[i].b2 = Adapter.adapt.adapter_address[1];
- pMacAddr[i].b3 = Adapter.adapt.adapter_address[2];
- pMacAddr[i].b4 = Adapter.adapt.adapter_address[3];
- pMacAddr[i].b5 = Adapter.adapt.adapter_address[4];
- pMacAddr[i].b6 = Adapter.adapt.adapter_address[5];
- }
- }
- }
- return num;
- }
- BOOL ClassNetSetting::GetSettingOfWinNT()
- {
- LONG lRtn;
- HKEY hMainKey;
- TCHAR szParameters[256];
- //获得域名,主机名和是否使用IP路由
- _tcscpy(szParameters,
- _T("SYSTEM\ControlSet001\Services\Tcpip\Parameters"));
- lRtn = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- szParameters, 0, KEY_READ, &hMainKey);
- if(lRtn == ERROR_SUCCESS)
- {
- DWORD dwType,dwDataSize = 256;
- ::RegQueryValueEx(hMainKey, _T("Domain"), NULL, &dwType,
- (LPBYTE)m_szDomain, &dwDataSize);
- dwDataSize = 256;
- ::RegQueryValueEx(hMainKey, _T("Hostname"), NULL, &dwType,
- (LPBYTE)m_szHostName, &dwDataSize);
- dwDataSize = 256;
- ::RegQueryValueEx(hMainKey, _T("IPEnableRouter"), NULL, &dwType,
- (LPBYTE)&m_IPEnableRouter, &dwDataSize);
- }
- ::RegCloseKey(hMainKey);
- //获得IP地址和DNS解析等其他设置
- HKEY hNetCard = NULL;
- m_TotalNetCards = GetMacAddress(m_MacAddr);
- lRtn = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- _T("SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards"),
- 0, KEY_READ, &hNetCard);
- if(lRtn != ERROR_SUCCESS) //此处失败就返回
- {
- if(hNetCard != NULL)
- ::RegCloseKey(hNetCard);
- return FALSE;
- }
- DWORD dwSubKeyNum=0, dwSubKeyLen=256;
- //得到子键的个数,通常与网卡个数相等
- lRtn = ::RegQueryInfoKey(hNetCard, NULL, NULL, NULL,
- &dwSubKeyNum, &dwSubKeyLen, NULL,NULL,NULL,NULL,NULL,NULL);
- if(lRtn == ERROR_SUCCESS)
- {
- m_TotalNetCards = dwSubKeyNum; //网卡个数以此为主
- LPTSTR lpszKeyName = new TCHAR[dwSubKeyLen + 1];
- DWORD dwSize;
- for(int i=0; i<(int)dwSubKeyNum; i++)
- {
- TCHAR szServiceName[256];
1.1.4 小试牛刀--编程实现获取MAC地址(4)
- HKEY hNewKey;
- DWORD dwType = REG_SZ,dwDataSize = 256;
- dwSize = dwSubKeyLen + 1;
- ::RegEnumKeyEx(hNetCard, i, lpszKeyName,
- &dwSize, NULL,NULL,NULL,NULL);
- lRtn = ::RegOpenKeyEx(hNetCard,lpszKeyName,0,KEY_READ,&hNewKey);
- if(lRtn == ERROR_SUCCESS)
- {
- lRtn = ::RegQueryValueEx(hNewKey, _T("Description"), NULL,
- &dwType, (LPBYTE)m_Cards[i].szDescription, &dwDataSize);
- dwDataSize = 256;
- lRtn = ::RegQueryValueEx(hNewKey, _T("ServiceName"), NULL,
- &dwType, (LPBYTE)szServiceName, &dwDataSize);
- if(lRtn == ERROR_SUCCESS)
- {
- TCHAR szNewKey[256];
- wsprintf(szNewKey, _T("%s\Interfaces\%s"),
- szParameters, szServiceName);
- HKEY hTcpKey;
- lRtn = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, szNewKey, 0,
- KEY_READ, &hTcpKey);
- if(lRtn == ERROR_SUCCESS)
- {
- dwDataSize = 256;
- ::RegQueryValueEx(hTcpKey, _T("DefaultGateway"), NULL,
- &dwType, (LPBYTE)m_Cards[i].szGateWay, &dwDataSize);
- ProcessMultiString(m_Cards[i].szGateWay, dwDataSize);
- dwDataSize = 256;
- ::RegQueryValueEx(hTcpKey, _T("IPAddress"), NULL,
- &dwType,(LPBYTE)m_Cards[i].szIpAddress,&dwDataSize);
- ProcessMultiString(m_Cards[i].szIpAddress,dwDataSize);
- dwDataSize = 256;
- ::RegQueryValueEx(hTcpKey, _T("SubnetMask"), NULL,
- &dwType, (LPBYTE)m_Cards[i].szIpMask, &dwDataSize);
- ProcessMultiString(m_Cards[i].szIpMask, dwDataSize);
- dwDataSize = 256;
- ::RegQueryValueEx(hTcpKey, _T("NameServer"), NULL,
- &dwType, (LPBYTE)m_Cards[i].szDNSNameServer,
- &dwDataSize);
- }
- ::RegCloseKey(hTcpKey);
- }
- }
- ::RegCloseKey(hNewKey);
- m_Cards[i].szMacAddr[0] = m_MacAddr[i].b1;
- m_Cards[i].szMacAddr[1] = m_MacAddr[i].b2;
- m_Cards[i].szMacAddr[2] = m_MacAddr[i].b3;
- m_Cards[i].szMacAddr[3] = m_MacAddr[i].b4;
- m_Cards[i].szMacAddr[4] = m_MacAddr[i].b5;
- m_Cards[i].szMacAddr[5] = m_MacAddr[i].b6;
- }
- delete []lpszKeyName;
- }
- ::RegCloseKey(hNetCard);
- return lRtn == ERROR_SUCCESS ? TRUE : FALSE;
- }
- UCHAR ClassNetSetting::GetAddressByIndex(int lana_num, ASTAT &Adapter)
- {
- NCB ncb;
- UCHAR uRetCode;
- memset(&ncb, 0, sizeof(ncb));
- ncb.ncb_command = NCBRESET;
- ncb.ncb_lana_num = lana_num;
- //指定网卡号,首先对选定的网卡发送一个NCBRESET命令,以便进行初始化
- uRetCode = Netbios(&ncb);
- memset(&ncb, 0, sizeof(ncb));
- ncb.ncb_command = NCBASTAT;
- ncb.ncb_lana_num = lana_num; //指定网卡号
- strcpy((char*)ncb.ncb_callname, "* " );
- ncb.ncb_buffer = (unsigned char *)&Adapter;
- //指定返回信息存放的变量
- ncb.ncb_length = sizeof(Adapter);
- //接着,可以发送NCBASTAT命令以获取网卡的信息
- uRetCode = Netbios(&ncb);
- return uRetCode;
- }
- void ClassNetSetting::ProcessMultiString(LPTSTR lpszString, DWORD dwSize)
- {
- for(int i=0; i<int(dwSize-2); i++)
- {
- if(lpszString[i] == _T(' '))
- lpszString[i] = _T(',');
- }
- }
到此为止,本实例的主要代码讲解完毕。执行后将首先显示网卡的类型,如图1-9所示。单击"确定"按钮,在弹出的窗体中可以查看此网卡的MAC地址,如图1-10所示。
![]() |
图1-9 获取网卡的类型 |
![]() |
图1-10 网卡详情 |