zoukankan      html  css  js  c++  java
  • 1.1.4 小试牛刀--编程实现获取MAC地址(1)

    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地址的结构。具体代码如下:

    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(''))  
    83. lpszString[i] = _T(',');  
    84. }  
    85. }  

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

     
    图1-9  获取网卡的类型
     
    图1-10  网卡详情
  • 相关阅读:
    Qt编写安防视频监控系统27-GPU显示
    Qt开源作品37-网络中转服务器
    【日拱一卒】链表——回文判断
    【日拱一卒】链表——判断链表是否有环
    【日拱一卒】链表——链表反转(递归解法)
    批处理文件bat设置环境变量path
    用来进行序列化和反序列化的工具类
    @JsonIgnoreProperties转换实体时忽略json中不存在的字段
    如何获取mac的ip地址
    objectMapper.convertValue
  • 原文地址:https://www.cnblogs.com/For-her/p/3939055.html
Copyright © 2011-2022 走看看