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