1*c2c66affSColin Finck /* 2*c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory 3*c2c66affSColin Finck * PROJECT: ReactOS ping utility 4*c2c66affSColin Finck * FILE: applications/cmdutils/arping/arping.c 5*c2c66affSColin Finck * PURPOSE: Network test utility 6*c2c66affSColin Finck * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org> 7*c2c66affSColin Finck */ 8*c2c66affSColin Finck 9*c2c66affSColin Finck #define WIN32_NO_STATUS 10*c2c66affSColin Finck #include <stdarg.h> 11*c2c66affSColin Finck #include <windef.h> 12*c2c66affSColin Finck #include <winbase.h> 13*c2c66affSColin Finck #include <winuser.h> 14*c2c66affSColin Finck #include <winnls.h> 15*c2c66affSColin Finck #include <wincon.h> 16*c2c66affSColin Finck #define _INC_WINDOWS 17*c2c66affSColin Finck #include <ws2tcpip.h> 18*c2c66affSColin Finck #include <iphlpapi.h> 19*c2c66affSColin Finck #include <ws2def.h> 20*c2c66affSColin Finck #include <stdio.h> 21*c2c66affSColin Finck #include <stdlib.h> 22*c2c66affSColin Finck 23*c2c66affSColin Finck #include "resource.h" 24*c2c66affSColin Finck 25*c2c66affSColin Finck BOOL NeverStop; 26*c2c66affSColin Finck UINT PingCount; 27*c2c66affSColin Finck WCHAR TargetName[256]; 28*c2c66affSColin Finck WCHAR SourceName[256]; 29*c2c66affSColin Finck DWORD SourceAddr; 30*c2c66affSColin Finck DWORD TargetAddr; 31*c2c66affSColin Finck WCHAR TargetIP[16]; 32*c2c66affSColin Finck WCHAR SourceIP[16]; 33*c2c66affSColin Finck SOCKADDR_IN Target; 34*c2c66affSColin Finck HANDLE hStdOutput; 35*c2c66affSColin Finck ULONG Timeout; 36*c2c66affSColin Finck LARGE_INTEGER TicksPerMs; 37*c2c66affSColin Finck LARGE_INTEGER TicksPerUs; 38*c2c66affSColin Finck BOOL UsePerformanceCounter; 39*c2c66affSColin Finck UINT Sent; 40*c2c66affSColin Finck UINT Received; 41*c2c66affSColin Finck 42*c2c66affSColin Finck void FormatOutput(UINT uID, ...) 43*c2c66affSColin Finck { 44*c2c66affSColin Finck va_list valist; 45*c2c66affSColin Finck 46*c2c66affSColin Finck WCHAR Buf[1024]; 47*c2c66affSColin Finck CHAR AnsiBuf[1024]; 48*c2c66affSColin Finck LPWSTR pBuf = Buf; 49*c2c66affSColin Finck PCHAR pAnsiBuf = AnsiBuf; 50*c2c66affSColin Finck WCHAR Format[1024]; 51*c2c66affSColin Finck DWORD written; 52*c2c66affSColin Finck UINT DataLength; 53*c2c66affSColin Finck int AnsiLength; 54*c2c66affSColin Finck 55*c2c66affSColin Finck if (!LoadString(GetModuleHandle(NULL), uID, 56*c2c66affSColin Finck Format, sizeof(Format) / sizeof(WCHAR))) 57*c2c66affSColin Finck { 58*c2c66affSColin Finck return; 59*c2c66affSColin Finck } 60*c2c66affSColin Finck 61*c2c66affSColin Finck va_start(valist, uID); 62*c2c66affSColin Finck 63*c2c66affSColin Finck DataLength = FormatMessage(FORMAT_MESSAGE_FROM_STRING, Format, 0, 0, Buf,\ 64*c2c66affSColin Finck sizeof(Buf) / sizeof(WCHAR), &valist); 65*c2c66affSColin Finck 66*c2c66affSColin Finck if(!DataLength) 67*c2c66affSColin Finck { 68*c2c66affSColin Finck if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) 69*c2c66affSColin Finck { 70*c2c66affSColin Finck va_end(valist); 71*c2c66affSColin Finck return; 72*c2c66affSColin Finck } 73*c2c66affSColin Finck 74*c2c66affSColin Finck DataLength = FormatMessage(FORMAT_MESSAGE_FROM_STRING |\ 75*c2c66affSColin Finck FORMAT_MESSAGE_ALLOCATE_BUFFER,\ 76*c2c66affSColin Finck Format, 0, 0, (LPWSTR)&pBuf, 0, &valist); 77*c2c66affSColin Finck } 78*c2c66affSColin Finck 79*c2c66affSColin Finck if(!DataLength) 80*c2c66affSColin Finck { 81*c2c66affSColin Finck va_end(valist); 82*c2c66affSColin Finck return; 83*c2c66affSColin Finck } 84*c2c66affSColin Finck 85*c2c66affSColin Finck if(GetFileType(hStdOutput) == FILE_TYPE_CHAR) 86*c2c66affSColin Finck { 87*c2c66affSColin Finck /* Is a console or a printer */ 88*c2c66affSColin Finck WriteConsole(hStdOutput, pBuf, DataLength, &written, NULL); 89*c2c66affSColin Finck } 90*c2c66affSColin Finck else 91*c2c66affSColin Finck { 92*c2c66affSColin Finck /* Is a pipe, socket, file or other */ 93*c2c66affSColin Finck AnsiLength = WideCharToMultiByte(CP_ACP, 0, pBuf, DataLength,\ 94*c2c66affSColin Finck NULL, 0, NULL, NULL); 95*c2c66affSColin Finck 96*c2c66affSColin Finck if(AnsiLength >= sizeof(AnsiBuf)) 97*c2c66affSColin Finck pAnsiBuf = (PCHAR)HeapAlloc(GetProcessHeap(), 0, AnsiLength); 98*c2c66affSColin Finck 99*c2c66affSColin Finck AnsiLength = WideCharToMultiByte(CP_OEMCP, 0, pBuf, DataLength,\ 100*c2c66affSColin Finck pAnsiBuf, AnsiLength, " ", NULL); 101*c2c66affSColin Finck 102*c2c66affSColin Finck WriteFile(hStdOutput, pAnsiBuf, AnsiLength, &written, NULL); 103*c2c66affSColin Finck 104*c2c66affSColin Finck if(pAnsiBuf != AnsiBuf) 105*c2c66affSColin Finck HeapFree(NULL, 0, pAnsiBuf); 106*c2c66affSColin Finck } 107*c2c66affSColin Finck 108*c2c66affSColin Finck if(pBuf != Buf) 109*c2c66affSColin Finck LocalFree(pBuf); 110*c2c66affSColin Finck } 111*c2c66affSColin Finck 112*c2c66affSColin Finck static VOID Usage(VOID) 113*c2c66affSColin Finck { 114*c2c66affSColin Finck FormatOutput(IDS_USAGE); 115*c2c66affSColin Finck } 116*c2c66affSColin Finck 117*c2c66affSColin Finck static BOOL ParseCmdline(int argc, LPWSTR argv[]) 118*c2c66affSColin Finck { 119*c2c66affSColin Finck INT i; 120*c2c66affSColin Finck 121*c2c66affSColin Finck if (argc < 3) 122*c2c66affSColin Finck { 123*c2c66affSColin Finck Usage(); 124*c2c66affSColin Finck return FALSE; 125*c2c66affSColin Finck } 126*c2c66affSColin Finck 127*c2c66affSColin Finck for (i = 1; i < argc; i++) 128*c2c66affSColin Finck { 129*c2c66affSColin Finck if (argv[i][0] == L'-' || argv[i][0] == L'/') 130*c2c66affSColin Finck { 131*c2c66affSColin Finck switch (argv[i][1]) 132*c2c66affSColin Finck { 133*c2c66affSColin Finck case L't': NeverStop = TRUE; break; 134*c2c66affSColin Finck case L'n': 135*c2c66affSColin Finck if (i + 1 < argc) 136*c2c66affSColin Finck { 137*c2c66affSColin Finck PingCount = wcstoul(argv[++i], NULL, 0); 138*c2c66affSColin Finck 139*c2c66affSColin Finck if (PingCount == 0) 140*c2c66affSColin Finck { 141*c2c66affSColin Finck FormatOutput(IDS_BAD_VALUE_OPTION_N, UINT_MAX); 142*c2c66affSColin Finck return FALSE; 143*c2c66affSColin Finck } 144*c2c66affSColin Finck } 145*c2c66affSColin Finck else 146*c2c66affSColin Finck { 147*c2c66affSColin Finck FormatOutput(IDS_BAD_OPTION_FORMAT, argv[i]); 148*c2c66affSColin Finck return FALSE; 149*c2c66affSColin Finck } 150*c2c66affSColin Finck break; 151*c2c66affSColin Finck 152*c2c66affSColin Finck case L's': 153*c2c66affSColin Finck if (SourceName[0] != 0) 154*c2c66affSColin Finck { 155*c2c66affSColin Finck FormatOutput(IDS_BAD_PARAMETER, argv[i]); 156*c2c66affSColin Finck return FALSE; 157*c2c66affSColin Finck } 158*c2c66affSColin Finck 159*c2c66affSColin Finck if (i + 1 < argc) 160*c2c66affSColin Finck { 161*c2c66affSColin Finck wcscpy(SourceName, argv[++i]); 162*c2c66affSColin Finck } 163*c2c66affSColin Finck else 164*c2c66affSColin Finck { 165*c2c66affSColin Finck FormatOutput(IDS_BAD_OPTION_FORMAT, argv[i]); 166*c2c66affSColin Finck return FALSE; 167*c2c66affSColin Finck } 168*c2c66affSColin Finck break; 169*c2c66affSColin Finck 170*c2c66affSColin Finck case '?': 171*c2c66affSColin Finck Usage(); 172*c2c66affSColin Finck return FALSE; 173*c2c66affSColin Finck 174*c2c66affSColin Finck default: 175*c2c66affSColin Finck FormatOutput(IDS_BAD_OPTION, argv[i]); 176*c2c66affSColin Finck return FALSE; 177*c2c66affSColin Finck } 178*c2c66affSColin Finck } 179*c2c66affSColin Finck else 180*c2c66affSColin Finck { 181*c2c66affSColin Finck if (TargetName[0] != 0) 182*c2c66affSColin Finck { 183*c2c66affSColin Finck FormatOutput(IDS_BAD_PARAMETER, argv[i]); 184*c2c66affSColin Finck return FALSE; 185*c2c66affSColin Finck } 186*c2c66affSColin Finck else 187*c2c66affSColin Finck { 188*c2c66affSColin Finck wcscpy(TargetName, argv[i]); 189*c2c66affSColin Finck } 190*c2c66affSColin Finck } 191*c2c66affSColin Finck } 192*c2c66affSColin Finck 193*c2c66affSColin Finck if (TargetName[0] == 0) 194*c2c66affSColin Finck { 195*c2c66affSColin Finck FormatOutput(IDS_DEST_MUST_BE_SPECIFIED); 196*c2c66affSColin Finck return FALSE; 197*c2c66affSColin Finck } 198*c2c66affSColin Finck 199*c2c66affSColin Finck if (SourceName[0] == 0) 200*c2c66affSColin Finck { 201*c2c66affSColin Finck FormatOutput(IDS_SRC_MUST_BE_SPECIFIED); 202*c2c66affSColin Finck return FALSE; 203*c2c66affSColin Finck } 204*c2c66affSColin Finck 205*c2c66affSColin Finck return TRUE; 206*c2c66affSColin Finck } 207*c2c66affSColin Finck 208*c2c66affSColin Finck static BOOL WINAPI StopLoop(DWORD dwCtrlType) 209*c2c66affSColin Finck { 210*c2c66affSColin Finck NeverStop = FALSE; 211*c2c66affSColin Finck PingCount = 0; 212*c2c66affSColin Finck 213*c2c66affSColin Finck return TRUE; 214*c2c66affSColin Finck } 215*c2c66affSColin Finck 216*c2c66affSColin Finck static BOOL Setup(VOID) 217*c2c66affSColin Finck { 218*c2c66affSColin Finck WORD wVersionRequested; 219*c2c66affSColin Finck WSADATA WsaData; 220*c2c66affSColin Finck INT Status; 221*c2c66affSColin Finck PHOSTENT phe; 222*c2c66affSColin Finck CHAR aTargetName[256]; 223*c2c66affSColin Finck IN_ADDR Target; 224*c2c66affSColin Finck 225*c2c66affSColin Finck wVersionRequested = MAKEWORD(2, 2); 226*c2c66affSColin Finck 227*c2c66affSColin Finck Status = WSAStartup(wVersionRequested, &WsaData); 228*c2c66affSColin Finck if (Status != 0) 229*c2c66affSColin Finck { 230*c2c66affSColin Finck FormatOutput(IDS_COULD_NOT_INIT_WINSOCK); 231*c2c66affSColin Finck return FALSE; 232*c2c66affSColin Finck } 233*c2c66affSColin Finck 234*c2c66affSColin Finck if (!WideCharToMultiByte(CP_ACP, 0, TargetName, -1, aTargetName, 235*c2c66affSColin Finck sizeof(aTargetName), NULL, NULL)) 236*c2c66affSColin Finck { 237*c2c66affSColin Finck FormatOutput(IDS_UNKNOWN_HOST, TargetName); 238*c2c66affSColin Finck return FALSE; 239*c2c66affSColin Finck } 240*c2c66affSColin Finck 241*c2c66affSColin Finck phe = NULL; 242*c2c66affSColin Finck TargetAddr = inet_addr(aTargetName); 243*c2c66affSColin Finck if (TargetAddr == INADDR_NONE) 244*c2c66affSColin Finck { 245*c2c66affSColin Finck phe = gethostbyname(aTargetName); 246*c2c66affSColin Finck if (phe == NULL) 247*c2c66affSColin Finck { 248*c2c66affSColin Finck FormatOutput(IDS_UNKNOWN_HOST, TargetName); 249*c2c66affSColin Finck return FALSE; 250*c2c66affSColin Finck } 251*c2c66affSColin Finck 252*c2c66affSColin Finck CopyMemory(&TargetAddr, phe->h_addr, phe->h_length); 253*c2c66affSColin Finck } 254*c2c66affSColin Finck 255*c2c66affSColin Finck Target.S_un.S_addr = TargetAddr; 256*c2c66affSColin Finck swprintf(TargetIP, L"%d.%d.%d.%d", Target.S_un.S_un_b.s_b1, 257*c2c66affSColin Finck Target.S_un.S_un_b.s_b2, 258*c2c66affSColin Finck Target.S_un.S_un_b.s_b3, 259*c2c66affSColin Finck Target.S_un.S_un_b.s_b4); 260*c2c66affSColin Finck 261*c2c66affSColin Finck if (!WideCharToMultiByte(CP_ACP, 0, SourceName, -1, aTargetName, 262*c2c66affSColin Finck sizeof(aTargetName), NULL, NULL)) 263*c2c66affSColin Finck { 264*c2c66affSColin Finck FormatOutput(IDS_UNKNOWN_HOST, SourceName); 265*c2c66affSColin Finck return FALSE; 266*c2c66affSColin Finck } 267*c2c66affSColin Finck 268*c2c66affSColin Finck SourceAddr = inet_addr(aTargetName); 269*c2c66affSColin Finck if (SourceAddr == INADDR_NONE) 270*c2c66affSColin Finck { 271*c2c66affSColin Finck FormatOutput(IDS_UNKNOWN_HOST, SourceName); 272*c2c66affSColin Finck return FALSE; 273*c2c66affSColin Finck } 274*c2c66affSColin Finck 275*c2c66affSColin Finck SetConsoleCtrlHandler(StopLoop, TRUE); 276*c2c66affSColin Finck 277*c2c66affSColin Finck return TRUE; 278*c2c66affSColin Finck } 279*c2c66affSColin Finck 280*c2c66affSColin Finck static VOID Cleanup(VOID) 281*c2c66affSColin Finck { 282*c2c66affSColin Finck WSACleanup(); 283*c2c66affSColin Finck } 284*c2c66affSColin Finck 285*c2c66affSColin Finck static VOID QueryTime(PLARGE_INTEGER Time) 286*c2c66affSColin Finck { 287*c2c66affSColin Finck if (UsePerformanceCounter) 288*c2c66affSColin Finck { 289*c2c66affSColin Finck if (QueryPerformanceCounter(Time) == 0) 290*c2c66affSColin Finck { 291*c2c66affSColin Finck /* This should not happen, but we fall 292*c2c66affSColin Finck back to GetCurrentTick() if it does */ 293*c2c66affSColin Finck Time->u.LowPart = (ULONG)GetTickCount(); 294*c2c66affSColin Finck Time->u.HighPart = 0; 295*c2c66affSColin Finck 296*c2c66affSColin Finck /* 1 tick per millisecond for GetCurrentTick() */ 297*c2c66affSColin Finck TicksPerMs.QuadPart = 1; 298*c2c66affSColin Finck /* GetCurrentTick() cannot handle microseconds */ 299*c2c66affSColin Finck TicksPerUs.QuadPart = 1; 300*c2c66affSColin Finck 301*c2c66affSColin Finck UsePerformanceCounter = FALSE; 302*c2c66affSColin Finck } 303*c2c66affSColin Finck } 304*c2c66affSColin Finck else 305*c2c66affSColin Finck { 306*c2c66affSColin Finck Time->u.LowPart = (ULONG)GetTickCount(); 307*c2c66affSColin Finck Time->u.HighPart = 0; 308*c2c66affSColin Finck } 309*c2c66affSColin Finck } 310*c2c66affSColin Finck 311*c2c66affSColin Finck static VOID TimeToMsString(LPWSTR String, ULONG Length, LARGE_INTEGER Time) 312*c2c66affSColin Finck { 313*c2c66affSColin Finck WCHAR Convstr[40]; 314*c2c66affSColin Finck LARGE_INTEGER LargeTime; 315*c2c66affSColin Finck LPWSTR ms; 316*c2c66affSColin Finck 317*c2c66affSColin Finck LargeTime.QuadPart = Time.QuadPart / TicksPerMs.QuadPart; 318*c2c66affSColin Finck 319*c2c66affSColin Finck _i64tow(LargeTime.QuadPart, Convstr, 10); 320*c2c66affSColin Finck wcscpy(String, Convstr); 321*c2c66affSColin Finck ms = String + wcslen(String); 322*c2c66affSColin Finck LoadString(GetModuleHandle(NULL), IDS_MS, ms, Length - (ms - String)); 323*c2c66affSColin Finck } 324*c2c66affSColin Finck 325*c2c66affSColin Finck static BOOL Ping(VOID) 326*c2c66affSColin Finck { 327*c2c66affSColin Finck LARGE_INTEGER RelativeTime; 328*c2c66affSColin Finck LARGE_INTEGER LargeTime; 329*c2c66affSColin Finck LARGE_INTEGER SentTime; 330*c2c66affSColin Finck DWORD Ret; 331*c2c66affSColin Finck BYTE TargetHW[6]; 332*c2c66affSColin Finck ULONG Size; 333*c2c66affSColin Finck WCHAR Sign[2]; 334*c2c66affSColin Finck WCHAR Time[100]; 335*c2c66affSColin Finck WCHAR StrHwAddr[18]; 336*c2c66affSColin Finck 337*c2c66affSColin Finck QueryTime(&SentTime); 338*c2c66affSColin Finck Size = sizeof(TargetHW); 339*c2c66affSColin Finck memset(TargetHW, 0xff, Size); 340*c2c66affSColin Finck ++Sent; 341*c2c66affSColin Finck Ret = SendARP(TargetAddr, SourceAddr, (PULONG)TargetHW, &Size); 342*c2c66affSColin Finck if (Ret == ERROR_SUCCESS) 343*c2c66affSColin Finck { 344*c2c66affSColin Finck QueryTime(&LargeTime); 345*c2c66affSColin Finck 346*c2c66affSColin Finck RelativeTime.QuadPart = (LargeTime.QuadPart - SentTime.QuadPart); 347*c2c66affSColin Finck 348*c2c66affSColin Finck if ((RelativeTime.QuadPart / TicksPerMs.QuadPart) < 1) 349*c2c66affSColin Finck { 350*c2c66affSColin Finck wcscpy(Sign, L"<"); 351*c2c66affSColin Finck LoadString(GetModuleHandle(NULL), IDS_1MS, Time, sizeof(Time) / sizeof(WCHAR)); 352*c2c66affSColin Finck } 353*c2c66affSColin Finck else 354*c2c66affSColin Finck { 355*c2c66affSColin Finck wcscpy(Sign, L"="); 356*c2c66affSColin Finck TimeToMsString(Time, sizeof(Time) / sizeof(WCHAR), RelativeTime); 357*c2c66affSColin Finck } 358*c2c66affSColin Finck 359*c2c66affSColin Finck swprintf(StrHwAddr, L"%02x:%02x:%02x:%02x:%02x:%02x", TargetHW[0], TargetHW[1], 360*c2c66affSColin Finck TargetHW[2], TargetHW[3], 361*c2c66affSColin Finck TargetHW[4], TargetHW[5]); 362*c2c66affSColin Finck FormatOutput(IDS_REPLY_FROM, TargetIP, StrHwAddr, Sign, Time); 363*c2c66affSColin Finck Received++; 364*c2c66affSColin Finck 365*c2c66affSColin Finck return TRUE; 366*c2c66affSColin Finck } 367*c2c66affSColin Finck 368*c2c66affSColin Finck return FALSE; 369*c2c66affSColin Finck } 370*c2c66affSColin Finck 371*c2c66affSColin Finck int wmain(int argc, LPWSTR argv[]) 372*c2c66affSColin Finck { 373*c2c66affSColin Finck UINT Count; 374*c2c66affSColin Finck LARGE_INTEGER PerformanceCounterFrequency; 375*c2c66affSColin Finck 376*c2c66affSColin Finck PingCount = 4; 377*c2c66affSColin Finck Timeout = 1000; 378*c2c66affSColin Finck hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 379*c2c66affSColin Finck 380*c2c66affSColin Finck UsePerformanceCounter = QueryPerformanceFrequency(&PerformanceCounterFrequency); 381*c2c66affSColin Finck 382*c2c66affSColin Finck if (UsePerformanceCounter) 383*c2c66affSColin Finck { 384*c2c66affSColin Finck /* Performance counters may return incorrect results on some multiprocessor 385*c2c66affSColin Finck platforms so we restrict execution on the first processor. This may fail 386*c2c66affSColin Finck on Windows NT so we fall back to GetCurrentTick() for timing */ 387*c2c66affSColin Finck if (SetThreadAffinityMask (GetCurrentThread(), 1) == 0) 388*c2c66affSColin Finck UsePerformanceCounter = FALSE; 389*c2c66affSColin Finck 390*c2c66affSColin Finck /* Convert frequency to ticks per millisecond */ 391*c2c66affSColin Finck TicksPerMs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000; 392*c2c66affSColin Finck /* And to ticks per microsecond */ 393*c2c66affSColin Finck TicksPerUs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000000; 394*c2c66affSColin Finck } 395*c2c66affSColin Finck if (!UsePerformanceCounter) 396*c2c66affSColin Finck { 397*c2c66affSColin Finck /* 1 tick per millisecond for GetCurrentTick() */ 398*c2c66affSColin Finck TicksPerMs.QuadPart = 1; 399*c2c66affSColin Finck /* GetCurrentTick() cannot handle microseconds */ 400*c2c66affSColin Finck TicksPerUs.QuadPart = 1; 401*c2c66affSColin Finck } 402*c2c66affSColin Finck 403*c2c66affSColin Finck if (!ParseCmdline(argc, argv) || !Setup()) 404*c2c66affSColin Finck { 405*c2c66affSColin Finck return 1; 406*c2c66affSColin Finck } 407*c2c66affSColin Finck 408*c2c66affSColin Finck FormatOutput(IDS_ARPING_TO_FROM, TargetIP, SourceName); 409*c2c66affSColin Finck 410*c2c66affSColin Finck Count = 0; 411*c2c66affSColin Finck while (Count < PingCount || NeverStop) 412*c2c66affSColin Finck { 413*c2c66affSColin Finck Ping(); 414*c2c66affSColin Finck Count++; 415*c2c66affSColin Finck if (Count < PingCount || NeverStop) 416*c2c66affSColin Finck Sleep(Timeout); 417*c2c66affSColin Finck } 418*c2c66affSColin Finck 419*c2c66affSColin Finck Cleanup(); 420*c2c66affSColin Finck 421*c2c66affSColin Finck FormatOutput(IDS_ARPING_STATISTICS, Sent, Received); 422*c2c66affSColin Finck 423*c2c66affSColin Finck return 0; 424*c2c66affSColin Finck } 425