首页 > 代码库 > 1.1.4 小试牛刀--编程实现获取MAC地址(1)

1.1.4 小试牛刀--编程实现获取MAC地址(1)

1.1.4  小试牛刀--编程实现获取MAC地址(1)

实例功能 使用Visual C++开发一个FTP传输系统

源码路径 光盘\yuanma\1\FTP

本实例的目的是,使用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地址的结构。具体代码如下:

  1. //操作系统类型  
  2. enum Win32Type {  
  3. Unknow,  
  4. Win32s,  
  5. Windows9X,  
  6. WinNT3,  
  7. WinNT4orHigher  
  8. };  
  9.  
  10. typedef struct tagASTAT   
  11. {   
  12. ADAPTER_STATUS adapt;   
  13. NAME_BUFFER  NameBuff[30];   
  14. } ASTAT, *LPASTAT;   
  15.  
  16. //存储网卡的MAC地址的结构  
  17. typedef struct tagMAC_ADDRESS  
  18. {  
  19. BYTE b1,b2,b3,b4,b5,b6;  
  20. } MAC_ADDRESS, *LPMAC_ADDRESS;  
  21.  
  22. //网卡信息的数据结构,包括记录网卡的厂商及型号,与之绑定的IP地址,网关,  
  23. //DNS序列,子网掩码和物理地址  
  24. typedef struct tagNET_CARD  
  25. {  
  26. TCHAR szDescription[256];  
  27. BYTE  szMacAddr[6];  
  28. TCHAR szGateWay[128];  
  29. TCHAR szIpAddress[128];  
  30. TCHAR szIpMask[128];  
  31. TCHAR szDNSNameServer[128];  
  32. } NET_CARD, *LPNET_CARD;  
  33.  
  34. class ClassNetSetting    
  35. {  
  36. public:  
  37. void ProcessMultiString(LPTSTR lpszString, DWORD dwSize);  
  38. UCHAR GetAddressByIndex(int lana_num, ASTAT &Adapter);  
  39. BOOL GetSettingOfWinNT();  
  40. int GetMacAddress(LPMAC_ADDRESS pMacAddr);  
  41. BOOL GetSetting();  
  42. ClassNetSetting();  
  43. virtual ~ClassNetSetting();  
  44. public:  
  45. BOOL GetSettingOfWin9X();  
  46. Win32Type GetSystemType();  
  47. int         m_TotalNetCards; //系统的网卡数  
  48. TCHAR       m_szDomain[16]; //域名  
  49. TCHAR       m_szHostName[16]; //主机名  
  50. int         m_IPEnableRouter; //是否允许IP路由: 0-不允许, 1-允许, 2-未知  
  51. int         m_EnableDNS; //是否允许DNS解析: 0-不允许, 1-允许, 2-未知  
  52. NET_CARD        m_Cards[MAX_CARD]; //默认的最大网卡数是10  
  53. Win32Type       m_SystemType; //操作系统类型  
  54. MAC_ADDRESS     m_MacAddr[MAX_CARD]; //允许10个网卡  
  55.  
  56. };  

(2) 编写文件ClassNetSetting.cpp,用于向网卡发送信息,以获取当前计算机的网卡数目和名称。具体代码如下:

  1. ClassNetSetting::ClassNetSetting()  
  2. {  
  3. m_TotalNetCards = 0;  
  4. _tcscpy(m_szDomain,_T(""));  
  5. _tcscpy(m_szHostName,_T(""));  
  6. m_IPEnableRouter = 2;  
  7. m_EnableDNS = 2;  
  8. m_SystemType = Unknow;  
  9. }  
  10.  
  11. ClassNetSetting::~ClassNetSetting()  
  12. {  
  13. }  
  14.  
  15. BOOL ClassNetSetting::GetSetting()  
  16. {  
  17. m_SystemType = GetSystemType();  
  18. if (m_SystemType == Windows9X)  
  19. return GetSettingOfWin9X();  
  20. else if(m_SystemType == WinNT4orHigher)  
  21. return GetSettingOfWinNT();  
  22. else //不支持老旧的操作系统  
  23. return FALSE;  
  24. }  
  25.  
  26. Win32Type ClassNetSetting::GetSystemType()  
  27. {  
  28. Win32Type  SystemType;  
  29. DWORD winVer;  
  30. OSVERSIONINFO *osvi;  
  31. winVer = GetVersion();  
  32. if(winVer 0x80000000)  
  33. {  
  34. /*NT */  
  35. SystemType = WinNT3;  
  36. osvi = (OSVERSIONINFO*)malloc(sizeof(OSVERSIONINFO));  
  37. if (osvi != NULL)  
  38. {  
  39. memset(osvi, 0, sizeof(OSVERSIONINFO));  
  40. osvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);  
  41. GetVersionEx(osvi);  
  42. if (osvi->dwMajorVersion >= 4L)  
  43. SystemType = WinNT4orHigher; //它是NT4或更高版本!  
  44. free(osvi);  
  45. }  
  46. }  
  47. else if (LOBYTE(LOWORD(winVer)) 4)  
  48. SystemType = Win32s; /*Win32s*/  
  49. else  
  50. SystemType = Windows9X; /*Windows9X*/  
  51. return SystemType;  
  52. }  
  53. BOOL ClassNetSetting::GetSettingOfWin9X()  
  54. {  
  55. LONG lRet;  
  56. HKEY hMainKey;  
  57. TCHAR szNameServer[256];  
  58.  
  59. //得到域名,网关和DNS的设置  
  60. lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,  
  61. _T("System\\CurrentControlSet\\Services\\VxD\\MSTCP"),  
  62. 0, KEY_READ, &hMainKey);  
  63. if(lRet == ERROR_SUCCESS)  
  64. {  
  65. DWORD dwType, dwDataSize=256;  
  66. ::RegQueryValueEx(hMainKey, _T("Domain"), NULL, &dwType,  
  67. (LPBYTE)m_szDomain, &dwDataSize);  
  68. dwDataSize = 256;  
  69. ::RegQueryValueEx(hMainKey, _T("Hostname"), NULL, &dwType,  
  70. (LPBYTE)m_szHostName, &dwDataSize);  
  71. dwDataSize = 256;  
  72. ::RegQueryValueEx(hMainKey, _T("EnableDNS"), NULL, &dwType,  
  73. (LPBYTE)&m_EnableDNS, &dwDataSize);  
  74. dwDataSize = 256;  
  75. ::RegQueryValueEx(hMainKey, _T("NameServer"), NULL, &dwType,  
  76. (LPBYTE)szNameServer, &dwDataSize);  
  77. }  
  78. ::RegCloseKey(hMainKey);  
  79.  
  80. HKEY hNetCard = NULL;  
  81. //调用CTcpCfg类的静态函数得到网卡的数目和相应的MAC地址  
  82. m_TotalNetCards = GetMacAddress(m_MacAddr);  
  83. lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,  
  84. _T("System\\CurrentControlSet\\Services\\Class\\Net"),  
  85. 0, KEY_READ, &hNetCard);  
  86. if(lRet != ERROR_SUCCESS) //此处失败就返回  
  87. {  
  88. if(hNetCard != NULL)  
  89. ::RegCloseKey(hNetCard);  
  90. return FALSE;  
  91. }  
  92. DWORD dwSubKeyNum = 0,dwSubKeyLen = 256;  
  93. //得到子键的个数,通常与网卡个数相等  
  94. lRet = ::RegQueryInfoKey(hNetCard, NULL, NULL, NULL,   
  95. &dwSubKeyNum, &dwSubKeyLen, NULL,NULL,NULL,NULL,NULL,NULL);  
  96. if(lRet == ERROR_SUCCESS)  
  97. {  
  98. //m_TotalNetCards = dwSubKeyNum; //网卡个数以此为主  
  99. LPTSTR lpszKeyName = new TCHAR[dwSubKeyLen + 1];  
  100. DWORD dwSize;  
  101. for(int i=0; i<(int)m_TotalNetCards; i++)  
  102. {  
  103. TCHAR szNewKey[256];  
  104. HKEY hNewKey;  
  105. DWORD dwType=REG_SZ, dwDataSize=256;  
  106. dwSize = dwSubKeyLen + 1;  
  107. lRet = ::RegEnumKeyEx(hNetCard, i, lpszKeyName,   
  108. &dwSize, NULL, NULL, NULL, NULL);  
  109. if(lRet == ERROR_SUCCESS)  
  110. {  
  111. lRet = ::RegOpenKeyEx(hNetCard,  
  112. lpszKeyName, 0, KEY_READ, &hNewKey);  
  113. if(lRet == ERROR_SUCCESS)  
  114. ::RegQueryValueEx(hNewKey, _T("DriverDesc"), NULL,  
  115. &dwType, (LPBYTE)m_Cards[i].szDescription, &dwDataSize);  
  116. ::RegCloseKey(hNewKey);  
  117. wsprintf(szNewKey,  
  118. _T("System\\CurrentControlSet\\Services\\Class\\NetTrans\\%s"),  
  119. lpszKeyName);  
  120. lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,  
  121. szNewKey, 0, KEY_READ, &hNewKey);  
  122. if(lRet == ERROR_SUCCESS)  
  123. {  
  124. dwDataSize = 256;  
  125. ::RegQueryValueEx(hNewKey, _T("DefaultGateway"), NULL,   
  126. &dwType, (LPBYTE)m_Cards[i].szGateWay, &dwDataSize);  
  127. ProcessMultiString(m_Cards[i].szGateWay, dwDataSize);  
  128. dwDataSize = 256;  

1.1.4  小试牛刀--编程实现获取MAC地址(3)

  1. ::RegQueryValueEx(hNewKey,_T("IPAddress"), NULL,  
  2. &dwType, (LPBYTE)m_Cards[i].szIpAddress, &dwDataSize);  
  3. ProcessMultiString(m_Cards[i].szIpAddress, dwDataSize);  
  4. dwDataSize = 256;  
  5. ::RegQueryValueEx(hNewKey, _T("IPMask"), NULL, &dwType,  
  6. (LPBYTE)m_Cards[i].szIpMask, &dwDataSize);  
  7. ProcessMultiString(m_Cards[i].szIpMask, dwDataSize);  
  8. //拷贝前面得到的DNS主机名  
  9. _tcscpy(m_Cards[i].szDNSNameServer, szNameServer);  
  10. }  
  11. ::RegCloseKey(hNewKey);  
  12. }  
  13. m_Cards[i].szMacAddr[0] = m_MacAddr[i].b1;  
  14. m_Cards[i].szMacAddr[1] = m_MacAddr[i].b2;  
  15. m_Cards[i].szMacAddr[2] = m_MacAddr[i].b3;  
  16. m_Cards[i].szMacAddr[3] = m_MacAddr[i].b4;  
  17. m_Cards[i].szMacAddr[4] = m_MacAddr[i].b5;  
  18. m_Cards[i].szMacAddr[5] = m_MacAddr[i].b6;  
  19. }  
  20. }  
  21. ::RegCloseKey(hNetCard);  
  22. return lRet == ERROR_SUCCESS ? TRUE : FALSE;  
  23. }  
  24. int ClassNetSetting::GetMacAddress(LPMAC_ADDRESS pMacAddr)  
  25. {  
  26. NCB ncb;   
  27. UCHAR uRetCode;  
  28. int num = 0;  
  29. LANA_ENUM lana_enum;   
  30. memset(&ncb, 0, sizeof(ncb));   
  31. ncb.ncb_command = NCBENUM;   
  32. ncb.ncb_buffer = (unsigned char *)&lana_enum;   
  33. ncb.ncb_length = sizeof(lana_enum);   
  34. //向网卡发送NCBENUM命令,以获取当前机器的网卡信息,如有多少个网卡,  
  35. //每张网卡的编号等   
  36. uRetCode = Netbios(&ncb);  
  37. if (uRetCode == 0)   
  38. {  
  39. num = lana_enum.length;  
  40. //对每一张网卡,以其网卡编号为输入编号,获取其MAC地址   
  41. for (int i=0; i<num; i++)  
  42. {  
  43. ASTAT Adapter;  
  44. if(GetAddressByIndex(lana_enum.lana[i],Adapter) == 0)  
  45. {  
  46. pMacAddr[i].b1 = Adapter.adapt.adapter_address[0];  
  47. pMacAddr[i].b2 = Adapter.adapt.adapter_address[1];  
  48. pMacAddr[i].b3 = Adapter.adapt.adapter_address[2];  
  49. pMacAddr[i].b4 = Adapter.adapt.adapter_address[3];  
  50. pMacAddr[i].b5 = Adapter.adapt.adapter_address[4];  
  51. pMacAddr[i].b6 = Adapter.adapt.adapter_address[5];  
  52. }  
  53. }  
  54. }  
  55. return num;  
  56. }  
  57. BOOL ClassNetSetting::GetSettingOfWinNT()  
  58. {  
  59. LONG lRtn;  
  60. HKEY hMainKey;  
  61. TCHAR szParameters[256];  
  62. //获得域名,主机名和是否使用IP路由  
  63. _tcscpy(szParameters,  
  64. _T("SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters"));  
  65. lRtn = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,  
  66. szParameters, 0, KEY_READ, &hMainKey);  
  67. if(lRtn == ERROR_SUCCESS)  
  68. {  
  69. DWORD dwType,dwDataSize = 256;  
  70. ::RegQueryValueEx(hMainKey, _T("Domain"), NULL, &dwType,  
  71. (LPBYTE)m_szDomain, &dwDataSize);  
  72. dwDataSize = 256;  
  73. ::RegQueryValueEx(hMainKey, _T("Hostname"), NULL, &dwType,  
  74. (LPBYTE)m_szHostName, &dwDataSize);  
  75. dwDataSize = 256;  
  76. ::RegQueryValueEx(hMainKey, _T("IPEnableRouter"), NULL, &dwType,  
  77. (LPBYTE)&m_IPEnableRouter, &dwDataSize);  
  78. }  
  79. ::RegCloseKey(hMainKey);  
  80.  
  81. //获得IP地址和DNS解析等其他设置  
  82. HKEY hNetCard = NULL;  
  83. m_TotalNetCards = GetMacAddress(m_MacAddr);  
  84. lRtn = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,  
  85. _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"),  
  86. 0, KEY_READ, &hNetCard);  
  87. if(lRtn != ERROR_SUCCESS) //此处失败就返回  
  88. {  
  89. if(hNetCard != NULL)  
  90. ::RegCloseKey(hNetCard);  
  91. return FALSE;  
  92. }  
  93. DWORD dwSubKeyNum=0, dwSubKeyLen=256;  
  94. //得到子键的个数,通常与网卡个数相等  
  95. lRtn = ::RegQueryInfoKey(hNetCard, NULL, NULL, NULL,  
  96. &dwSubKeyNum, &dwSubKeyLen, NULL,NULL,NULL,NULL,NULL,NULL);  
  97. if(lRtn == ERROR_SUCCESS)  
  98. {  
  99. m_TotalNetCards = dwSubKeyNum; //网卡个数以此为主  
  100. LPTSTR lpszKeyName = new TCHAR[dwSubKeyLen + 1];  
  101. DWORD dwSize;  
  102. for(int i=0; i<(int)dwSubKeyNum; i++)  
  103. {  
  104. TCHAR szServiceName[256];  

1.1.4  小试牛刀--编程实现获取MAC地址(4)

  1. HKEY hNewKey;  
  2. DWORD dwType = REG_SZ,dwDataSize = 256;  
  3. dwSize = dwSubKeyLen + 1;  
  4. ::RegEnumKeyEx(hNetCard, i, lpszKeyName,  
  5. &dwSize, NULL,NULL,NULL,NULL);  
  6. lRtn = ::RegOpenKeyEx(hNetCard,lpszKeyName,0,KEY_READ,&hNewKey);  
  7. if(lRtn == ERROR_SUCCESS)  
  8. {  
  9. lRtn = ::RegQueryValueEx(hNewKey, _T("Description"), NULL,  
  10. &dwType, (LPBYTE)m_Cards[i].szDescription, &dwDataSize);  
  11. dwDataSize = 256;  
  12. lRtn = ::RegQueryValueEx(hNewKey, _T("ServiceName"), NULL,  
  13. &dwType, (LPBYTE)szServiceName, &dwDataSize);  
  14. if(lRtn == ERROR_SUCCESS)  
  15. {  
  16. TCHAR szNewKey[256];  
  17. wsprintf(szNewKey, _T("%s\\Interfaces\\%s"),  
  18. szParameters, szServiceName);  
  19. HKEY hTcpKey;  
  20. lRtn = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, szNewKey, 0,  
  21. KEY_READ, &hTcpKey);  
  22. if(lRtn == ERROR_SUCCESS)  
  23. {  
  24. dwDataSize = 256;  
  25. ::RegQueryValueEx(hTcpKey, _T("DefaultGateway"), NULL,  
  26. &dwType, (LPBYTE)m_Cards[i].szGateWay, &dwDataSize);  
  27. ProcessMultiString(m_Cards[i].szGateWay, dwDataSize);  
  28. dwDataSize = 256;  
  29. ::RegQueryValueEx(hTcpKey, _T("IPAddress"), NULL,   
  30. &dwType,(LPBYTE)m_Cards[i].szIpAddress,&dwDataSize);  
  31. ProcessMultiString(m_Cards[i].szIpAddress,dwDataSize);  
  32. dwDataSize = 256;  
  33. ::RegQueryValueEx(hTcpKey, _T("SubnetMask"), NULL,   
  34. &dwType, (LPBYTE)m_Cards[i].szIpMask, &dwDataSize);  
  35. ProcessMultiString(m_Cards[i].szIpMask, dwDataSize);  
  36. dwDataSize = 256;  
  37. ::RegQueryValueEx(hTcpKey, _T("NameServer"), NULL,   
  38. &dwType, (LPBYTE)m_Cards[i].szDNSNameServer,   
  39. &dwDataSize);  
  40. }  
  41. ::RegCloseKey(hTcpKey);  
  42. }  
  43. }  
  44. ::RegCloseKey(hNewKey);  
  45. m_Cards[i].szMacAddr[0] = m_MacAddr[i].b1;  
  46. m_Cards[i].szMacAddr[1] = m_MacAddr[i].b2;  
  47. m_Cards[i].szMacAddr[2] = m_MacAddr[i].b3;  
  48. m_Cards[i].szMacAddr[3] = m_MacAddr[i].b4;  
  49. m_Cards[i].szMacAddr[4] = m_MacAddr[i].b5;  
  50. m_Cards[i].szMacAddr[5] = m_MacAddr[i].b6;  
  51. }  
  52. delete []lpszKeyName;  
  53. }  
  54. ::RegCloseKey(hNetCard);  
  55. return lRtn == ERROR_SUCCESS ? TRUE : FALSE;  
  56. }  
  57. UCHAR ClassNetSetting::GetAddressByIndex(int lana_num, ASTAT &Adapter)  
  58. {  
  59. NCB ncb;   
  60. UCHAR uRetCode;   
  61. memset(&ncb, 0, sizeof(ncb));   
  62. ncb.ncb_command = NCBRESET;   
  63. ncb.ncb_lana_num = lana_num;   
  64. //指定网卡号,首先对选定的网卡发送一个NCBRESET命令,以便进行初始化   
  65. uRetCode = Netbios(&ncb);   
  66. memset(&ncb, 0, sizeof(ncb));   
  67. ncb.ncb_command = NCBASTAT;   
  68. ncb.ncb_lana_num = lana_num;   //指定网卡号   
  69. strcpy((char*)ncb.ncb_callname, "*      " );   
  70. ncb.ncb_buffer = (unsigned char *)&Adapter;   
  71. //指定返回信息存放的变量   
  72. ncb.ncb_length = sizeof(Adapter);   
  73. //接着,可以发送NCBASTAT命令以获取网卡的信息   
  74. uRetCode = Netbios(&ncb);   
  75. return uRetCode;  
  76. }   
  77.  
  78. void ClassNetSetting::ProcessMultiString(LPTSTR lpszString, DWORD dwSize)  
  79. {   
  80. for(int i=0; i<int(dwSize-2); i++)  
  81. {  
  82. if(lpszString[i] == _T(‘\0‘))  
  83. lpszString[i] = _T(‘,‘);  
  84. }  
  85. }  

到此为止,本实例的主要代码讲解完毕。执行后将首先显示网卡的类型,如图1-9所示。单击"确定"按钮,在弹出的窗体中可以查看此网卡的MAC地址,如图1-10所示。

 
图1-9  获取网卡的类型
 
图1-10  网卡详情

1.1.4 小试牛刀--编程实现获取MAC地址(1)