1 /*
2    This program is free software; you can redistribute it and/or modify
3    it under the terms of the GNU General Public License as published by
4    the Free Software Foundation; either version 2 of the License, or
5    (at your option) any later version.
6 
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11 
12    You should have received a copy of the GNU General Public License
13    along with this program; if not, write to the Free Software
14    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16 /* Copyright (C) 2007, Dmitry Chapyshev <lentind@yandex.ru> */
17 /* Copyright (C) 2011, Rafal Harabien <rafalh1992@o2.pl> */
18 
19 #include <wchar.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdarg.h>
23 #include <windows.h>
24 #include <time.h>
25 #include <locale.h>
26 #include <lm.h>
27 #include <shlwapi.h>
28 #include <iphlpapi.h>
29 #include <winsock2.h>
30 #include <udmihelp.h>
31 
32 #include "resource.h"
33 
34 #define BUFFER_SIZE 1024
35 
36 /* Load string from registry */
37 static
38 unsigned
39 RegGetSZ(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName, LPWSTR lpBuf, DWORD cchBuf)
40 {
41     DWORD dwBytes = cchBuf*sizeof(WCHAR), dwType = 0;
42     unsigned cChars;
43 
44     /* If SubKey is specified open it */
45     if (lpSubKey && RegOpenKeyExW(hKey,
46                                   lpSubKey,
47                                   0,
48                                   KEY_QUERY_VALUE,
49                                   &hKey) != ERROR_SUCCESS)
50     {
51         wprintf(L"Warning! Cannot open %s. Last error: %lu.\n", lpSubKey, GetLastError());
52         return 0;
53     }
54 
55     /* Query registry value and check its type */
56     if (RegQueryValueExW(hKey,
57                          lpValueName,
58                          NULL,
59                          &dwType,
60                          (LPBYTE)lpBuf,
61                          &dwBytes) != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_MULTI_SZ))
62     {
63         wprintf(L"Warning! Cannot query %s. Last error: %lu, type: %lu.\n", lpValueName, GetLastError(), dwType);
64         dwBytes = 0;
65     }
66     else if (dwBytes == 0)
67     {
68         wcscpy(lpBuf, L"N/A");
69         dwBytes = 6;
70     }
71 
72     /* Close key if we opened it */
73     if (lpSubKey)
74         RegCloseKey(hKey);
75 
76     cChars = dwBytes/sizeof(WCHAR);
77 
78     /* NULL-terminate string */
79     lpBuf[min(cchBuf-1, cChars)] = L'\0';
80 
81     /* Don't count NULL characters */
82     while(cChars && !lpBuf[cChars-1])
83         --cChars;
84 
85     return cChars;
86 }
87 
88 /* Load DWORD from registry */
89 static
90 BOOL
91 RegGetDWORD(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName, LPDWORD lpData)
92 {
93     DWORD dwBytes = sizeof(*lpData), dwType;
94     BOOL bRet = TRUE;
95 
96     /* If SubKey is specified open it */
97     if (lpSubKey && RegOpenKeyExW(hKey,
98                                  lpSubKey,
99                                  0,
100                                  KEY_QUERY_VALUE,
101                                  &hKey) != ERROR_SUCCESS)
102     {
103         wprintf(L"Warning! Cannot open %s. Last error: %lu.\n", lpSubKey, GetLastError());
104         return FALSE;
105     }
106 
107     /* Query registry value and check its type */
108     if (RegQueryValueExW(hKey,
109                          lpValueName,
110                          NULL,
111                          &dwType,
112                          (LPBYTE)lpData,
113                          &dwBytes) != ERROR_SUCCESS || dwType != REG_DWORD)
114     {
115         wprintf(L"Warning! Cannot query %s. Last err: %lu, type: %lu\n", lpValueName, GetLastError(), dwType);
116         *lpData = 0;
117         bRet = FALSE;
118     }
119 
120     /* Close key if we opened it */
121     if (lpSubKey)
122         RegCloseKey(hKey);
123 
124     return bRet;
125 }
126 
127 /* Format bytes */
128 static
129 VOID
130 FormatBytes(LPWSTR lpBuf, unsigned cBytes)
131 {
132     WCHAR szMB[32];
133     NUMBERFMTW fmt;
134     unsigned i;
135 
136     _itow(cBytes / (1024*1024), szMB, 10);
137 
138     fmt.NumDigits = 0;
139     fmt.LeadingZero = 0;
140     fmt.Grouping = 3;
141     fmt.lpDecimalSep = L"";
142     fmt.lpThousandSep = L" ";
143     fmt.NegativeOrder = 0;
144 
145     i = GetNumberFormatW(LOCALE_SYSTEM_DEFAULT, 0, szMB, &fmt, lpBuf, BUFFER_SIZE - 3);
146     if (i)
147         --i; /* don't count NULL character */
148     wcscpy(lpBuf + i, L" MB");
149 }
150 
151 /* Format date and time */
152 static
153 VOID
154 FormatDateTime(time_t Time, LPWSTR lpBuf)
155 {
156     unsigned i;
157     SYSTEMTIME SysTime;
158     const struct tm *lpTm;
159 
160     lpTm = localtime(&Time);
161     SysTime.wYear = (WORD)(1900 + lpTm->tm_year);
162     SysTime.wMonth = (WORD)(1 + lpTm->tm_mon);
163     SysTime.wDayOfWeek = (WORD)lpTm->tm_wday;
164     SysTime.wDay = (WORD)lpTm->tm_mday;
165     SysTime.wHour = (WORD)lpTm->tm_hour;
166     SysTime.wMinute = (WORD)lpTm->tm_min;
167     SysTime.wSecond = (WORD)lpTm->tm_sec;
168     SysTime.wMilliseconds = 0;
169 
170     /* Copy date first */
171     i = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &SysTime, NULL, lpBuf, BUFFER_SIZE - 2);
172     if (i)
173         --i; /* don't count NULL character */
174 
175     /* Copy time now */
176     i += swprintf(lpBuf + i, L", ");
177 
178     GetTimeFormatW(LOCALE_SYSTEM_DEFAULT, 0, &SysTime, NULL, lpBuf + i, BUFFER_SIZE - i);
179 }
180 
181 ULONGLONG GetSecondsQPC(VOID)
182 {
183     LARGE_INTEGER Counter, Frequency;
184 
185     QueryPerformanceCounter(&Counter);
186     QueryPerformanceFrequency(&Frequency);
187 
188     return Counter.QuadPart / Frequency.QuadPart;
189 }
190 
191 ULONGLONG GetSeconds(VOID)
192 {
193     ULONGLONG (WINAPI * pGetTickCount64)(VOID);
194     ULONGLONG Ticks64;
195     HMODULE hModule = GetModuleHandleW(L"kernel32.dll");
196 
197     pGetTickCount64 = (PVOID)GetProcAddress(hModule, "GetTickCount64");
198     if (pGetTickCount64)
199     {
200         return pGetTickCount64() / 1000;
201     }
202 
203     hModule = LoadLibraryW(L"kernel32_vista.dll");
204 
205     if (!hModule)
206     {
207         return GetSecondsQPC();
208     }
209 
210     pGetTickCount64 = (PVOID)GetProcAddress(hModule, "GetTickCount64");
211 
212     if (pGetTickCount64)
213     {
214         Ticks64 = pGetTickCount64() / 1000;
215     }
216     else
217     {
218         Ticks64 = GetSecondsQPC();
219     }
220 
221     FreeLibrary(hModule);
222     return Ticks64;
223 }
224 
225 /* Show usage */
226 static
227 VOID
228 Usage(VOID)
229 {
230     WCHAR Buf[4096];
231     if (LoadStringW(GetModuleHandle(NULL), IDS_USAGE, Buf, 4096))
232         wprintf(L"%s", Buf);
233 }
234 
235 static
236 VOID
237 PrintRow(UINT nTitleID, BOOL bIndent, LPWSTR lpFormat, ...)
238 {
239     WCHAR Buf[BUFFER_SIZE];
240     va_list Args;
241     unsigned c;
242 
243     if (nTitleID)
244     {
245         c = LoadStringW(GetModuleHandle(NULL), nTitleID, Buf, BUFFER_SIZE - 2);
246         if (!c)
247             return;
248 
249         wcscpy(Buf + c, L": ");
250     } else
251         Buf[0] = L'\0';
252 
253     if (!bIndent)
254         wprintf(L"%-32s", Buf);
255     else if (Buf[0])
256         wprintf(L"%38s%-16s", L"", Buf);
257     else
258         wprintf(L"%38s", L"");
259 
260     va_start(Args, lpFormat);
261     vwprintf(lpFormat, Args);
262     va_end(Args);
263 
264     wprintf(L"\n");
265 }
266 
267 /* Print all system information */
268 VOID
269 AllSysInfo(VOID)
270 {
271     DWORD dwCharCount = BUFFER_SIZE, dwTimestamp, dwResult;
272     OSVERSIONINFOW VersionInfo;
273     SYSTEM_INFO SysInfo;
274     WCHAR Buf[BUFFER_SIZE], Tmp[BUFFER_SIZE], szSystemDir[MAX_PATH];
275     const WCHAR *lpcszSysType;
276     LPWSTR lpBuffer;
277     NETSETUP_JOIN_STATUS NetJoinStatus;
278     MEMORYSTATUS MemoryStatus;
279     unsigned int cSeconds, i, j;
280     TIME_ZONE_INFORMATION TimeZoneInfo;
281     HKEY hKey;
282     PIP_ADAPTER_ADDRESSES pAdapters;
283     ULONG cbAdapters;
284     PVOID SMBiosBuf;
285     PCHAR DmiStrings[ID_STRINGS_MAX] = { 0 };
286 
287     if (!GetSystemDirectoryW(szSystemDir, sizeof(szSystemDir)/sizeof(szSystemDir[0])))
288     {
289         wprintf(L"Error! GetSystemDirectory failed.\n");
290         return;
291     }
292 
293     GetSystemInfo(&SysInfo);
294 
295     // getting computer name
296     dwCharCount = BUFFER_SIZE;
297     if (!GetComputerNameW(Buf, &dwCharCount))
298         wprintf(L"Error! GetComputerName failed.\n");
299     else
300         PrintRow(IDS_HOST_NAME, FALSE, L"%s", Buf);
301 
302     // open CurrentVersion key
303     if(RegOpenKeyExW(HKEY_LOCAL_MACHINE,
304                     L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
305                     0,
306                     KEY_QUERY_VALUE,
307                     &hKey) != ERROR_SUCCESS)
308     {
309         wprintf(L"Error! RegOpenKeyEx failed.\n");
310         return;
311     }
312 
313     //getting OS Name
314     RegGetSZ(hKey, NULL, L"ProductName", Buf, BUFFER_SIZE);
315     PrintRow(IDS_OS_NAME, FALSE, L"%s", Buf);
316 
317     //getting OS Version
318     ZeroMemory(&VersionInfo, sizeof(VersionInfo));
319     VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
320     GetVersionExW(&VersionInfo);
321 
322     if (!LoadStringW(GetModuleHandle(NULL), IDS_BUILD, Tmp, BUFFER_SIZE))
323         Tmp[0] = L'\0';
324     PrintRow(IDS_OS_VERSION,
325              FALSE,
326              L"%lu.%lu.%lu %s %s %lu",
327              VersionInfo.dwMajorVersion,
328              VersionInfo.dwMinorVersion,
329              VersionInfo.dwBuildNumber,
330              VersionInfo.szCSDVersion,
331              Tmp,
332              VersionInfo.dwBuildNumber);
333 
334     //getting OS Manufacturer
335 
336     //getting OS Configuration
337 
338     //getting OS Build Type
339     RegGetSZ(hKey, NULL, L"CurrentType", Buf, BUFFER_SIZE);
340     PrintRow(IDS_OS_BUILD_TYPE, FALSE, L"%s", Buf);
341 
342     //getting Registered Owner
343     RegGetSZ(hKey, NULL, L"RegisteredOwner", Buf, BUFFER_SIZE);
344     PrintRow(IDS_REG_OWNER, FALSE, L"%s", Buf);
345 
346     //getting Registered Organization
347     RegGetSZ(hKey, NULL, L"RegisteredOrganization", Buf, BUFFER_SIZE);
348     PrintRow(IDS_REG_ORG, FALSE, L"%s", Buf);
349 
350     //getting Product ID
351     RegGetSZ(hKey, NULL, L"ProductId", Buf, BUFFER_SIZE);
352     PrintRow(IDS_PRODUCT_ID, FALSE, L"%s", Buf);
353 
354     //getting Install Date
355     RegGetDWORD(hKey, NULL, L"InstallDate", &dwTimestamp);
356     FormatDateTime((time_t)dwTimestamp, Buf);
357     PrintRow(IDS_INST_DATE, FALSE, L"%s", Buf);
358 
359     // close Current Version key now
360     RegCloseKey(hKey);
361 
362     //getting System Up Time
363     cSeconds = GetSeconds();
364     if (!LoadStringW(GetModuleHandle(NULL), IDS_UP_TIME_FORMAT, Tmp, BUFFER_SIZE))
365         Tmp[0] = L'\0';
366     swprintf(Buf, Tmp, cSeconds / (60*60*24), (cSeconds / (60*60)) % 24, (cSeconds / 60) % 60, cSeconds % 60);
367     PrintRow(IDS_UP_TIME, FALSE, L"%s", Buf);
368 
369     // prepare SMBIOS data
370     SMBiosBuf = LoadSMBiosData(DmiStrings);
371 
372     //getting System Manufacturer; HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation\Manufacturer for Win >= 6.0
373     swprintf(Tmp, L"%s\\oeminfo.ini", szSystemDir);
374     GetPrivateProfileStringW(L"General",
375                              L"Manufacturer",
376                              L"",
377                              Buf,
378                              sizeof(Buf)/sizeof(Buf[0]),
379                              Tmp);
380     if (wcslen(Buf) == 0 && SMBiosBuf)
381     {
382         GetSMBiosStringW(DmiStrings[SYS_VENDOR], Buf, _countof(Buf), FALSE);
383     }
384     PrintRow(IDS_SYS_MANUFACTURER, FALSE, L"%s", Buf);
385 
386     //getting System Model; HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation\Model for Win >= 6.0
387     GetPrivateProfileStringW(L"General",
388                              L"Model",
389                              L"",
390                              Buf,
391                              sizeof(Buf)/sizeof(Buf[0]),
392                              Tmp);
393     if (wcslen(Buf) == 0 && SMBiosBuf)
394     {
395         GetSMBiosStringW(DmiStrings[SYS_PRODUCT], Buf, _countof(Buf), FALSE);
396     }
397     PrintRow(IDS_SYS_MODEL, FALSE, L"%s", Buf);
398 
399     //getting System type
400     switch (SysInfo.wProcessorArchitecture)
401     {
402         case PROCESSOR_ARCHITECTURE_INTEL:
403             lpcszSysType = L"X86-based PC";
404             break;
405         case PROCESSOR_ARCHITECTURE_IA64:
406             lpcszSysType = L"IA64-based PC";
407             break;
408         case PROCESSOR_ARCHITECTURE_AMD64:
409             lpcszSysType = L"AMD64-based PC";
410             break;
411         default:
412             lpcszSysType = L"Unknown";
413             break;
414     }
415     PrintRow(IDS_SYS_TYPE, FALSE, L"%s", lpcszSysType);
416 
417     //getting Processor(s)
418     if (!LoadStringW(GetModuleHandle(NULL), IDS_PROCESSORS_FORMAT, Tmp, BUFFER_SIZE))
419         Tmp[0] = L'\0';
420     swprintf(Buf, Tmp, (unsigned)SysInfo.dwNumberOfProcessors);
421     PrintRow(IDS_PROCESSORS, FALSE, L"%s", Buf);
422     for(i = 0; i < (unsigned int)SysInfo.dwNumberOfProcessors; i++)
423     {
424         swprintf(Tmp, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%u", i);
425         j = swprintf(Buf, L"[%02u]: ", i + 1);
426 
427         j += RegGetSZ(HKEY_LOCAL_MACHINE, Tmp, L"Identifier", Buf + j, BUFFER_SIZE - j);
428         if(j + 1 < BUFFER_SIZE)
429             Buf[j++] = L' ';
430         RegGetSZ(HKEY_LOCAL_MACHINE, Tmp, L"VendorIdentifier", Buf + j, BUFFER_SIZE - j);
431 
432         PrintRow(0, FALSE, L"%s", Buf);
433     }
434 
435     //getting BIOS Version
436     if (SMBiosBuf)
437     {
438         j = GetSMBiosStringW(DmiStrings[BIOS_VENDOR], Buf, BUFFER_SIZE, TRUE);
439         if (j + 1 < BUFFER_SIZE)
440         {
441             Buf[j++] = L' ';
442             Buf[j] = L'\0';
443         }
444         GetSMBiosStringW(DmiStrings[BIOS_VERSION], Buf + j, BUFFER_SIZE - j, TRUE);
445     }
446     else
447     {
448         RegGetSZ(HKEY_LOCAL_MACHINE,
449                  L"HARDWARE\\DESCRIPTION\\System",
450                  L"SystemBiosVersion",
451                  Buf,
452                  BUFFER_SIZE);
453     }
454     PrintRow(IDS_BIOS_VERSION, FALSE, L"%s", Buf);
455 
456     //gettings BIOS date
457     if (SMBiosBuf)
458     {
459         GetSMBiosStringW(DmiStrings[BIOS_DATE], Buf, BUFFER_SIZE, TRUE);
460     }
461     else
462     {
463         RegGetSZ(HKEY_LOCAL_MACHINE,
464                  L"HARDWARE\\DESCRIPTION\\System",
465                  L"SystemBiosDate",
466                  Buf,
467                  BUFFER_SIZE);
468     }
469     PrintRow(IDS_BIOS_DATE, FALSE, L"%s", Buf);
470 
471     // clean SMBIOS data
472     FreeSMBiosData(SMBiosBuf);
473 
474     //getting ReactOS Directory
475     if (!GetWindowsDirectoryW(Buf, BUFFER_SIZE))
476         wprintf(L"Error! GetWindowsDirectory failed.");
477     else
478         PrintRow(IDS_ROS_DIR, FALSE, L"%s", Buf);
479 
480     //getting System Directory
481     PrintRow(IDS_SYS_DIR, 0, L"%s", szSystemDir);
482 
483     //getting Boot Device
484     RegGetSZ(HKEY_LOCAL_MACHINE,
485              L"SYSTEM\\Setup",
486              L"SystemPartition",
487              Buf,
488              BUFFER_SIZE);
489     PrintRow(IDS_BOOT_DEV, FALSE, L"%s", Buf);
490 
491     //getting System Locale
492     if (GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, Tmp, BUFFER_SIZE))
493         if (RegGetSZ(HKEY_CLASSES_ROOT,
494                      L"MIME\\Database\\Rfc1766",
495                      Tmp,
496                      Buf,
497                      BUFFER_SIZE))
498         {
499             /* get rid of @filename,resource */
500             lpBuffer = wcschr(Buf, L';');
501             if (lpBuffer)
502                 SHLoadIndirectString(lpBuffer+1, lpBuffer+1, BUFFER_SIZE - (lpBuffer-Buf) - 1, NULL);
503 
504             PrintRow(IDS_SYS_LOCALE, FALSE, L"%s", Buf);
505         }
506 
507     //getting Input Locale
508     if (RegGetSZ(HKEY_CURRENT_USER,
509                  L"Keyboard Layout\\Preload",
510                  L"1",
511                  Tmp,
512                  BUFFER_SIZE) && wcslen(Tmp) > 4)
513         if (RegGetSZ(HKEY_CLASSES_ROOT,
514                      L"MIME\\Database\\Rfc1766",
515                      Tmp + 4,
516                      Buf,
517                      BUFFER_SIZE))
518         {
519             /* get rid of @filename,resource */
520             lpBuffer = wcschr(Buf, L';');
521             if (lpBuffer)
522                 SHLoadIndirectString(lpBuffer+1, lpBuffer+1, BUFFER_SIZE - (lpBuffer-Buf) - 1, NULL);
523 
524             PrintRow(IDS_INPUT_LOCALE, FALSE, L"%s", Buf);
525         }
526 
527     //getting Time Zone
528     GetTimeZoneInformation(&TimeZoneInfo);
529 
530     /* Open Time Zones key */
531     if(RegOpenKeyExW(HKEY_LOCAL_MACHINE,
532                      L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
533                      0,
534                      KEY_ENUMERATE_SUB_KEYS|KEY_READ,
535                      &hKey) == ERROR_SUCCESS)
536     {
537         unsigned i;
538 
539         /* Find current timezone */
540         dwCharCount = BUFFER_SIZE;
541         for(i = 0; RegEnumKeyExW(hKey, i, Tmp, &dwCharCount, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; ++i, dwCharCount = 255)
542         {
543             RegGetSZ(hKey, Tmp, L"Std", Buf, BUFFER_SIZE);
544 
545             if (!wcscmp(Buf, TimeZoneInfo.StandardName))
546             {
547                 RegGetSZ(hKey, Tmp, L"Display", Buf, BUFFER_SIZE);
548 
549                 PrintRow(IDS_TIME_ZONE, FALSE, L"%s", Buf);
550 
551                 break;
552             }
553         }
554         RegCloseKey(hKey);
555     }
556 
557     //getting Total Physical Memory
558     GlobalMemoryStatus(&MemoryStatus);
559     FormatBytes(Buf, MemoryStatus.dwTotalPhys);
560     PrintRow(IDS_TOTAL_PHYS_MEM, FALSE, L"%s", Buf);
561 
562     //getting Available Physical Memory
563     FormatBytes(Buf, MemoryStatus.dwAvailPhys);
564     PrintRow(IDS_AVAIL_PHISICAL_MEM, FALSE, L"%s", Buf);
565 
566     //getting Virtual Memory: Max Size
567     FormatBytes(Buf, MemoryStatus.dwTotalVirtual);
568     PrintRow(IDS_VIRT_MEM_MAX, FALSE, L"%s", Buf);
569 
570     //getting Virtual Memory: Available
571     FormatBytes(Buf, MemoryStatus.dwAvailVirtual);
572     PrintRow(IDS_VIRT_MEM_AVAIL, FALSE, L"%s", Buf);
573 
574     //getting Virtual Memory: In Use
575     FormatBytes(Buf, MemoryStatus.dwTotalVirtual-MemoryStatus.dwAvailVirtual);
576     PrintRow(IDS_VIRT_MEM_INUSE, FALSE, L"%s", Buf);
577 
578     //getting Page File Location(s)
579     if (RegGetSZ(HKEY_LOCAL_MACHINE,
580                  L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management",
581                  L"PagingFiles",
582                  Buf,
583                  BUFFER_SIZE))
584     {
585         int i;
586 
587         for(i = 0; Buf[i]; i++)
588         {
589             if (Buf[i] == L' ')
590             {
591                 Buf[i] = L'\0';
592                 break;
593             }
594         }
595 
596         PrintRow(IDS_PAGEFILE_LOC, FALSE, L"%s", Buf);
597     }
598 
599     //getting Domain
600     if (NetGetJoinInformation (NULL, &lpBuffer, &NetJoinStatus) == NERR_Success)
601     {
602         if (NetJoinStatus == NetSetupWorkgroupName || NetJoinStatus == NetSetupDomainName)
603             PrintRow(IDS_DOMAIN, FALSE, L"%s", lpBuffer);
604 
605         NetApiBufferFree(lpBuffer);
606     }
607 
608     //getting Logon Server
609 
610     //getting NetWork Card(s)
611     cbAdapters = 4096;
612     pAdapters = malloc(cbAdapters);
613     while((dwResult = GetAdaptersAddresses(AF_UNSPEC, 0x0002, NULL, pAdapters, &cbAdapters)) == ERROR_BUFFER_OVERFLOW)
614     {
615         cbAdapters += 4096;
616         pAdapters = (PIP_ADAPTER_ADDRESSES)realloc(pAdapters, cbAdapters);
617     }
618 
619     if (dwResult == ERROR_SUCCESS)
620     {
621         PIP_ADAPTER_ADDRESSES pCurrentAdapter = pAdapters;
622         unsigned cAdapters = 0;
623 
624         /* Count adapters */
625         for(i = 0; pCurrentAdapter; ++i)
626         {
627             if (pCurrentAdapter->IfType != 24 && pCurrentAdapter->IfType != 131)
628                 ++cAdapters;
629             pCurrentAdapter = pCurrentAdapter->Next;
630         }
631 
632 
633         /* Print adapters count */
634         if (!LoadStringW(GetModuleHandle(NULL), IDS_NETWORK_CARDS_FORMAT, Tmp, BUFFER_SIZE))
635             Tmp[0] = L'\0';
636         swprintf(Buf, Tmp, cAdapters);
637         PrintRow(IDS_NETWORK_CARDS, FALSE, L"%s", Buf);
638 
639         /* Show information about each adapter */
640         pCurrentAdapter = pAdapters;
641         for(i = 0; pCurrentAdapter; ++i)
642         {
643             if (pCurrentAdapter->IfType != 24 && pCurrentAdapter->IfType != 131)//IF_TYPE_SOFTWARE_LOOPBACK)
644             {
645                 PIP_ADAPTER_UNICAST_ADDRESS pAddress;
646 
647                 PrintRow(0, FALSE, L"[%02u]: %s", i + 1, pCurrentAdapter->Description);
648                 PrintRow(IDS_CONNECTION_NAME, TRUE, L"%s", pCurrentAdapter->FriendlyName);
649                 if (!(pCurrentAdapter->Flags & 0x0004))
650                 {
651                     if (!LoadStringW(GetModuleHandle(NULL), IDS_NO, Buf, BUFFER_SIZE))
652                         Buf[0] = L'\0';
653                     PrintRow(IDS_DHCP_ENABLED, TRUE, Buf);
654                 }
655                 if (pCurrentAdapter->OperStatus == IfOperStatusDown)
656                 {
657                     if (!LoadStringW(GetModuleHandle(NULL), IDS_MEDIA_DISCONNECTED, Buf, BUFFER_SIZE))
658                         Buf[0] = L'\0';
659                     PrintRow(IDS_STATUS, TRUE, Buf);
660                 }
661                 else
662                 {
663                     if (!LoadStringW(GetModuleHandle(NULL), IDS_IP_ADDRESSES, Buf, BUFFER_SIZE))
664                         Buf[0] = L'\0';
665                     PrintRow(0, TRUE, Buf);
666                     pAddress = pCurrentAdapter->FirstUnicastAddress;
667                     for (j = 0; pAddress; ++j)
668                     {
669                         dwCharCount = BUFFER_SIZE;
670                         WSAAddressToStringW(pAddress->Address.lpSockaddr, pAddress->Address.iSockaddrLength, NULL, Buf, &dwCharCount);
671                         PrintRow(0, TRUE, L"[%02u]: %s", j + 1, Buf);
672                         pAddress = pAddress->Next;
673                     }
674                 }
675             }
676             pCurrentAdapter = pCurrentAdapter->Next;
677         }
678     }
679     free(pAdapters);
680 }
681 
682 /* Main program */
683 int
684 main(int argc, char *argv[])
685 {
686     WSADATA WsaData;
687     int i;
688 
689     setlocale(LC_ALL, "");
690 
691     WSAStartup(MAKEWORD(2, 2), &WsaData);
692 
693     for (i = 1; i < argc; ++i)
694     {
695         if (!strcmp(argv[i], "/?") || !strcmp(argv[i], "-?"))
696         {
697             Usage();
698             return 0;
699         }
700         else
701         {
702             printf("Unsupported argument: %s\n", argv[i]);
703             return -1;
704         }
705     }
706 
707     AllSysInfo();
708 
709     return 0;
710 }
711