在之前的隨筆http://www.cnblogs.com/annie-fun/p/6393149.html中,存在一些問題。本篇隨筆是為了糾正之前隨筆中的問題而寫的。
代碼改進之處有兩點:
第一、某一次WMI查詢失敗后,繼續執行查詢下一個字段,而不是直接返回;
第二、采用GetAdaptersInfo()函數查詢有線物理網卡的mac地址。
話不多說,直接看代碼~.~
頭文件UserInfo.h:

1 #pragma once 2 #include "stdafx.h" 3 #define _WIN32_DCOM 4 #include <comdef.h> 5 #include <Wbemidl.h> 6 # pragma comment(lib, "wbemuuid.lib") 7 #include <iphlpapi.h> 8 #pragma comment(lib, "IPHLPAPI.lib") 9 #include <stdio.h> 10 #include <windows.h> 11 using namespace std; 12 13 typedef struct UserInfo_t 14 { 15 char CpuID[20]; //CPU序列號 16 char BaseBoardID[256]; //主板ID 17 char SystemDiskID[256]; //系統所在硬盤的序列號 18 char BIOSID[20]; //BIOS序列號 19 char MacAddress[20]; //MAC地址 20 }UserInfo; 21 22 int GetUserInfo(UserInfo &info);
源代碼GetUerInfo.cpp:

1 #include "UserInfo.h" 2 3 void Trims(char* data) //去掉字符串中的空格 4 { 5 int i=-1,j=0; 6 int ch = ' '; 7 8 while(data[++i] != '\0') 9 { 10 if(data[i] != ch) 11 { 12 data[j++] = data[i]; 13 } 14 } 15 data[j] = '\0'; 16 } 17 18 int GetUserInfo(UserInfo &info) 19 { 20 HRESULT hres; 21 memset(&info,0x00,sizeof(UserInfo)); 22 23 CoUninitialize(); 24 hres = CoInitializeEx(0, COINIT_MULTITHREADED); //第二個參數設置當前線程的並發模式為多線程 25 //hres = CoInitializeEx(0,COINIT_APARTMENTTHREADED); //並發模式為單線程(即只能在單線程函數中調用GetUserInfo()) 26 if (FAILED(hres)) 27 { 28 return -1; 29 } 30 hres = CoInitializeSecurity( 31 NULL, 32 -1, 33 NULL, 34 NULL, 35 RPC_C_AUTHN_LEVEL_DEFAULT, 36 RPC_C_IMP_LEVEL_IMPERSONATE, 37 NULL, 38 EOAC_NONE, 39 NULL 40 ); 41 if (FAILED(hres)) 42 { 43 CoUninitialize(); 44 return -2; 45 } 46 IWbemLocator *pLoc = NULL; 47 hres = CoCreateInstance( 48 CLSID_WbemLocator, 49 0, 50 CLSCTX_INPROC_SERVER, 51 IID_IWbemLocator, (LPVOID *) &pLoc); 52 if (FAILED(hres)) 53 { 54 CoUninitialize(); 55 return -3; 56 } 57 IWbemServices *pSvc = NULL; 58 hres = pLoc->ConnectServer( 59 _bstr_t(L"ROOT\\CIMV2"), 60 NULL, 61 NULL, 62 0, 63 NULL, 64 0, 65 0, 66 &pSvc 67 ); 68 if (FAILED(hres)) 69 { 70 pLoc->Release(); 71 CoUninitialize(); 72 return -4; 73 } 74 hres = CoSetProxyBlanket( 75 pSvc, 76 RPC_C_AUTHN_WINNT, 77 RPC_C_AUTHZ_NONE, 78 NULL, 79 RPC_C_AUTHN_LEVEL_CALL, 80 RPC_C_IMP_LEVEL_IMPERSONATE, 81 NULL, 82 EOAC_NONE 83 ); 84 if (FAILED(hres)) 85 { 86 pSvc->Release(); 87 pLoc->Release(); 88 CoUninitialize(); 89 return -5; 90 } 91 92 IEnumWbemClassObject* pEnumerator = NULL; 93 IWbemClassObject *pclsObj; 94 ULONG uReturn = 0; 95 //獲取CPUID 96 hres = pSvc->ExecQuery( 97 bstr_t("WQL"), 98 bstr_t("SELECT * FROM win32_Processor"), 99 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 100 NULL, 101 &pEnumerator); 102 if ( !FAILED(hres)) 103 { 104 while (pEnumerator) 105 { 106 HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 107 if(0 == uReturn) 108 { 109 break; 110 } 111 VARIANT vtProp; 112 hr = pclsObj->Get(L"ProcessorId", 0, &vtProp, 0, 0); 113 wcstombs(info.CpuID,vtProp.bstrVal,20); 114 VariantClear(&vtProp); 115 pclsObj->Release(); 116 } 117 } 118 119 //獲取主板序列號---在某些電腦上獲取不到,則UserInfo結構體中該字段為空 120 pEnumerator->Release(); 121 pEnumerator=NULL; 122 hres = pSvc->ExecQuery( 123 bstr_t("WQL"), 124 bstr_t("SELECT * FROM Win32_BaseBoard"), 125 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 126 NULL, 127 &pEnumerator); 128 if (!FAILED(hres)) 129 { 130 while (pEnumerator) 131 { 132 HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 133 if(0 == uReturn) 134 { 135 break; 136 } 137 VARIANT vtProp; 138 hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); 139 wcstombs(info.BaseBoardID,vtProp.bstrVal,256); 140 VariantClear(&vtProp); 141 pclsObj->Release(); 142 } 143 } 144 145 //獲取系統所在硬盤的索引號 146 int diskIndex = 0; 147 pEnumerator->Release(); 148 pEnumerator=NULL; 149 hres = pSvc->ExecQuery( 150 bstr_t("WQL"), 151 bstr_t("SELECT * FROM Win32_DiskPartition WHERE Bootable = TRUE"), //查找啟動盤 152 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 153 NULL, 154 &pEnumerator); 155 if (!FAILED(hres)) 156 { 157 while (pEnumerator) 158 { 159 HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 160 if(0 == uReturn) 161 { 162 break; 163 } 164 VARIANT vtProp; 165 hr = pclsObj->Get(L"DiskIndex", 0, &vtProp, 0, 0); 166 diskIndex = vtProp.intVal; 167 VariantClear(&vtProp); 168 pclsObj->Release(); 169 } 170 171 //根據系統所在硬盤的索引號查詢硬盤序列號 172 char index[10]; 173 string strQuery = "SELECT * FROM Win32_DiskDrive WHERE Index = "; 174 itoa(diskIndex,index,10); 175 string indexStr(index); 176 strQuery += indexStr; 177 pEnumerator->Release(); 178 pEnumerator=NULL; 179 hres = pSvc->ExecQuery( 180 bstr_t("WQL"), 181 bstr_t(strQuery.c_str()), 182 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 183 NULL, 184 &pEnumerator); 185 if (!FAILED(hres)) 186 { 187 while (pEnumerator) 188 { 189 HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 190 if(0 == uReturn) 191 { 192 break; 193 } 194 VARIANT vtProp; 195 hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); 196 wcstombs(info.SystemDiskID,vtProp.bstrVal,256); 197 Trims(info.SystemDiskID); 198 VariantClear(&vtProp); 199 pclsObj->Release(); 200 } 201 } 202 } 203 204 //獲取BIOS序列號 205 pEnumerator->Release(); 206 pEnumerator=NULL; 207 hres = pSvc->ExecQuery( 208 bstr_t("WQL"), 209 bstr_t("SELECT * FROM Win32_BIOS"), 210 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 211 NULL, 212 &pEnumerator); 213 if (!FAILED(hres)) 214 { 215 while (pEnumerator) 216 { 217 HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn); 218 if(0 == uReturn) 219 { 220 break; 221 } 222 VARIANT vtProp; 223 hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); 224 wcstombs(info.BIOSID,vtProp.bstrVal,20); 225 VariantClear(&vtProp); 226 pclsObj->Release(); 227 } 228 } 229 230 //使用GetAdaptersInfo()函數獲得網卡信息,從而獲取本地連接的MAC地址 231 ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO); 232 PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO)); 233 if(pAdapterInfo == NULL) 234 return -1; 235 if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) 236 { 237 free(pAdapterInfo); 238 pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen); 239 if (pAdapterInfo == NULL) 240 return -2; 241 } 242 if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == NO_ERROR) 243 { 244 for(PIP_ADAPTER_INFO pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next) 245 { 246 // 如果不是有線物理網卡,直接跳過 247 if(pAdapter->Type != MIB_IF_TYPE_ETHERNET || pAdapter->Type == 71 ||strstr(pAdapter->Description,"Bluetooth") >0 ) 248 continue; 249 if(pAdapter->AddressLength != 6) 250 continue; 251 sprintf_s(info.MacAddress, 18, "%02X:%02X:%02X:%02X:%02X:%02X", 252 int (pAdapter->Address[0]), 253 int (pAdapter->Address[1]), 254 int (pAdapter->Address[2]), 255 int (pAdapter->Address[3]), 256 int (pAdapter->Address[4]), 257 int (pAdapter->Address[5])); 258 break; 259 } 260 } 261 free(pAdapterInfo); 262 263 pSvc->Release(); 264 pLoc->Release(); 265 pEnumerator->Release(); 266 CoUninitialize(); 267 268 return 0; 269 }
改進后的代碼仍存在不能獲取到主板序列號的可能性問題,目前沒找到較好的解決辦法。