[REACTOS]
[reactos.git] / rostests / winetests / iphlpapi / iphlpapi.c
1 /*
2 * iphlpapi dll test
3 *
4 * Copyright (C) 2003 Juan Lang
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 /*
22 * Some observations that an automated test can't produce:
23 * An adapter index is a key for an adapter. That is, if an index is returned
24 * from one API, that same index may be used successfully in another API, as
25 * long as the adapter remains present.
26 * If the adapter is removed and reinserted, however, the index may change (and
27 * indeed it does change on Win2K).
28 *
29 * The Name field of the IP_ADAPTER_INDEX_MAP entries returned by
30 * GetInterfaceInfo is declared as a wide string, but the bytes are actually
31 * an ASCII string on some versions of the IP helper API under Win9x. This was
32 * apparently an MS bug, it's corrected in later versions.
33 *
34 * The DomainName field of FIXED_INFO isn't NULL-terminated on Win98.
35 */
36
37 #include <stdarg.h>
38 #include "winsock2.h"
39 #include "windef.h"
40 #include "winbase.h"
41 #include "iphlpapi.h"
42 #include "iprtrmib.h"
43 #include "wine/test.h"
44 #include <stdio.h>
45 #include <stdlib.h>
46
47 #undef htonl
48 #undef htons
49 #undef ntohl
50 #undef ntohs
51
52 #define htonl(l) ((u_long)(l))
53 #define htons(s) ((u_short)(s))
54 #define ntohl(l) ((u_long)(l))
55 #define ntohs(s) ((u_short)(s))
56
57 static HMODULE hLibrary = NULL;
58
59 typedef DWORD (WINAPI *GetNumberOfInterfacesFunc)(PDWORD);
60 typedef DWORD (WINAPI *GetIpAddrTableFunc)(PMIB_IPADDRTABLE,PULONG,BOOL);
61 typedef DWORD (WINAPI *GetIfEntryFunc)(PMIB_IFROW);
62 typedef DWORD (WINAPI *GetFriendlyIfIndexFunc)(DWORD);
63 typedef DWORD (WINAPI *GetIfTableFunc)(PMIB_IFTABLE,PULONG,BOOL);
64 typedef DWORD (WINAPI *GetIpForwardTableFunc)(PMIB_IPFORWARDTABLE,PULONG,BOOL);
65 typedef DWORD (WINAPI *GetIpNetTableFunc)(PMIB_IPNETTABLE,PULONG,BOOL);
66 typedef DWORD (WINAPI *GetInterfaceInfoFunc)(PIP_INTERFACE_INFO,PULONG);
67 typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO,PULONG);
68 typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO,PULONG);
69 typedef DWORD (WINAPI *GetIcmpStatisticsFunc)(PMIB_ICMP);
70 typedef DWORD (WINAPI *GetIpStatisticsFunc)(PMIB_IPSTATS);
71 typedef DWORD (WINAPI *GetTcpStatisticsFunc)(PMIB_TCPSTATS);
72 typedef DWORD (WINAPI *GetUdpStatisticsFunc)(PMIB_UDPSTATS);
73 typedef DWORD (WINAPI *GetTcpTableFunc)(PMIB_TCPTABLE,PDWORD,BOOL);
74 typedef DWORD (WINAPI *GetUdpTableFunc)(PMIB_UDPTABLE,PDWORD,BOOL);
75 typedef DWORD (WINAPI *GetPerAdapterInfoFunc)(ULONG,PIP_PER_ADAPTER_INFO,PULONG);
76 typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(ULONG,ULONG,PVOID,PIP_ADAPTER_ADDRESSES,PULONG);
77 typedef DWORD (WINAPI *NotifyAddrChangeFunc)(PHANDLE,LPOVERLAPPED);
78 typedef BOOL (WINAPI *CancelIPChangeNotifyFunc)(LPOVERLAPPED);
79
80 static GetNumberOfInterfacesFunc gGetNumberOfInterfaces = NULL;
81 static GetIpAddrTableFunc gGetIpAddrTable = NULL;
82 static GetIfEntryFunc gGetIfEntry = NULL;
83 static GetFriendlyIfIndexFunc gGetFriendlyIfIndex = NULL;
84 static GetIfTableFunc gGetIfTable = NULL;
85 static GetIpForwardTableFunc gGetIpForwardTable = NULL;
86 static GetIpNetTableFunc gGetIpNetTable = NULL;
87 static GetInterfaceInfoFunc gGetInterfaceInfo = NULL;
88 static GetAdaptersInfoFunc gGetAdaptersInfo = NULL;
89 static GetNetworkParamsFunc gGetNetworkParams = NULL;
90 static GetIcmpStatisticsFunc gGetIcmpStatistics = NULL;
91 static GetIpStatisticsFunc gGetIpStatistics = NULL;
92 static GetTcpStatisticsFunc gGetTcpStatistics = NULL;
93 static GetUdpStatisticsFunc gGetUdpStatistics = NULL;
94 static GetTcpTableFunc gGetTcpTable = NULL;
95 static GetUdpTableFunc gGetUdpTable = NULL;
96 static GetPerAdapterInfoFunc gGetPerAdapterInfo = NULL;
97 static GetAdaptersAddressesFunc gGetAdaptersAddresses = NULL;
98 static NotifyAddrChangeFunc gNotifyAddrChange = NULL;
99 static CancelIPChangeNotifyFunc gCancelIPChangeNotify = NULL;
100
101 static void loadIPHlpApi(void)
102 {
103 hLibrary = LoadLibraryA("iphlpapi.dll");
104 if (hLibrary) {
105 gGetNumberOfInterfaces = (GetNumberOfInterfacesFunc)GetProcAddress(
106 hLibrary, "GetNumberOfInterfaces");
107 gGetIpAddrTable = (GetIpAddrTableFunc)GetProcAddress(
108 hLibrary, "GetIpAddrTable");
109 gGetIfEntry = (GetIfEntryFunc)GetProcAddress(
110 hLibrary, "GetIfEntry");
111 gGetFriendlyIfIndex = (GetFriendlyIfIndexFunc)GetProcAddress(
112 hLibrary, "GetFriendlyIfIndex");
113 gGetIfTable = (GetIfTableFunc)GetProcAddress(
114 hLibrary, "GetIfTable");
115 gGetIpForwardTable = (GetIpForwardTableFunc)GetProcAddress(
116 hLibrary, "GetIpForwardTable");
117 gGetIpNetTable = (GetIpNetTableFunc)GetProcAddress(
118 hLibrary, "GetIpNetTable");
119 gGetInterfaceInfo = (GetInterfaceInfoFunc)GetProcAddress(
120 hLibrary, "GetInterfaceInfo");
121 gGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress(
122 hLibrary, "GetAdaptersInfo");
123 gGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(
124 hLibrary, "GetNetworkParams");
125 gGetIcmpStatistics = (GetIcmpStatisticsFunc)GetProcAddress(
126 hLibrary, "GetIcmpStatistics");
127 gGetIpStatistics = (GetIpStatisticsFunc)GetProcAddress(
128 hLibrary, "GetIpStatistics");
129 gGetTcpStatistics = (GetTcpStatisticsFunc)GetProcAddress(
130 hLibrary, "GetTcpStatistics");
131 gGetUdpStatistics = (GetUdpStatisticsFunc)GetProcAddress(
132 hLibrary, "GetUdpStatistics");
133 gGetTcpTable = (GetTcpTableFunc)GetProcAddress(
134 hLibrary, "GetTcpTable");
135 gGetUdpTable = (GetUdpTableFunc)GetProcAddress(
136 hLibrary, "GetUdpTable");
137 gGetPerAdapterInfo = (GetPerAdapterInfoFunc)GetProcAddress(hLibrary, "GetPerAdapterInfo");
138 gGetAdaptersAddresses = (GetAdaptersAddressesFunc)GetProcAddress(hLibrary, "GetAdaptersAddresses");
139 gNotifyAddrChange = (NotifyAddrChangeFunc)GetProcAddress(
140 hLibrary, "NotifyAddrChange");
141 gCancelIPChangeNotify = (CancelIPChangeNotifyFunc)GetProcAddress(
142 hLibrary, "CancelIPChangeNotify");
143 }
144 }
145
146 static void freeIPHlpApi(void)
147 {
148 if (hLibrary) {
149 gGetNumberOfInterfaces = NULL;
150 gGetIpAddrTable = NULL;
151 gGetIfEntry = NULL;
152 gGetFriendlyIfIndex = NULL;
153 gGetIfTable = NULL;
154 gGetIpForwardTable = NULL;
155 gGetIpNetTable = NULL;
156 gGetInterfaceInfo = NULL;
157 gGetAdaptersInfo = NULL;
158 gGetNetworkParams = NULL;
159 gGetIcmpStatistics = NULL;
160 gGetIpStatistics = NULL;
161 gGetTcpStatistics = NULL;
162 gGetUdpStatistics = NULL;
163 gGetTcpTable = NULL;
164 gGetUdpTable = NULL;
165 gNotifyAddrChange = NULL;
166 gCancelIPChangeNotify = NULL;
167 FreeLibrary(hLibrary);
168 hLibrary = NULL;
169 }
170 }
171
172 /* replacement for inet_ntoa */
173 static const char *ntoa( DWORD ip )
174 {
175 static char buffer[40];
176
177 ip = htonl(ip);
178 sprintf( buffer, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff );
179 return buffer;
180 }
181
182 /*
183 still-to-be-tested 98-only functions:
184 GetUniDirectionalAdapterInfo
185 */
186 static void testWin98OnlyFunctions(void)
187 {
188 }
189
190 static void testGetNumberOfInterfaces(void)
191 {
192 if (gGetNumberOfInterfaces) {
193 DWORD apiReturn, numInterfaces;
194
195 /* Crashes on Vista */
196 if (0) {
197 apiReturn = gGetNumberOfInterfaces(NULL);
198 if (apiReturn == ERROR_NOT_SUPPORTED)
199 return;
200 ok(apiReturn == ERROR_INVALID_PARAMETER,
201 "GetNumberOfInterfaces(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
202 apiReturn);
203 }
204
205 apiReturn = gGetNumberOfInterfaces(&numInterfaces);
206 if (apiReturn == ERROR_NOT_SUPPORTED) {
207 skip("GetNumberOfInterfaces is not supported\n");
208 return;
209 }
210 ok(apiReturn == NO_ERROR,
211 "GetNumberOfInterfaces returned %d, expected 0\n", apiReturn);
212 }
213 }
214
215 static void testGetIfEntry(DWORD index)
216 {
217 if (gGetIfEntry) {
218 DWORD apiReturn;
219 MIB_IFROW row;
220
221 memset(&row, 0, sizeof(row));
222 apiReturn = gGetIfEntry(NULL);
223 if (apiReturn == ERROR_NOT_SUPPORTED) {
224 skip("GetIfEntry is not supported\n");
225 return;
226 }
227 ok(apiReturn == ERROR_INVALID_PARAMETER,
228 "GetIfEntry(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
229 apiReturn);
230 row.dwIndex = -1; /* hope that's always bogus! */
231 apiReturn = gGetIfEntry(&row);
232 ok(apiReturn == ERROR_INVALID_DATA ||
233 apiReturn == ERROR_FILE_NOT_FOUND /* Vista */,
234 "GetIfEntry(bogus row) returned %d, expected ERROR_INVALID_DATA or ERROR_FILE_NOT_FOUND\n",
235 apiReturn);
236 row.dwIndex = index;
237 apiReturn = gGetIfEntry(&row);
238 ok(apiReturn == NO_ERROR,
239 "GetIfEntry returned %d, expected NO_ERROR\n", apiReturn);
240 }
241 }
242
243 static void testGetIpAddrTable(void)
244 {
245 if (gGetIpAddrTable) {
246 DWORD apiReturn;
247 ULONG dwSize = 0;
248
249 apiReturn = gGetIpAddrTable(NULL, NULL, FALSE);
250 if (apiReturn == ERROR_NOT_SUPPORTED) {
251 skip("GetIpAddrTable is not supported\n");
252 return;
253 }
254 ok(apiReturn == ERROR_INVALID_PARAMETER,
255 "GetIpAddrTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
256 apiReturn);
257 apiReturn = gGetIpAddrTable(NULL, &dwSize, FALSE);
258 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
259 "GetIpAddrTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
260 apiReturn);
261 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
262 PMIB_IPADDRTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
263
264 apiReturn = gGetIpAddrTable(buf, &dwSize, FALSE);
265 ok(apiReturn == NO_ERROR,
266 "GetIpAddrTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
267 apiReturn);
268 if (apiReturn == NO_ERROR && buf->dwNumEntries)
269 testGetIfEntry(buf->table[0].dwIndex);
270 HeapFree(GetProcessHeap(), 0, buf);
271 }
272 }
273 }
274
275 static void testGetIfTable(void)
276 {
277 if (gGetIfTable) {
278 DWORD apiReturn;
279 ULONG dwSize = 0;
280
281 apiReturn = gGetIfTable(NULL, NULL, FALSE);
282 if (apiReturn == ERROR_NOT_SUPPORTED) {
283 skip("GetIfTable is not supported\n");
284 return;
285 }
286 ok(apiReturn == ERROR_INVALID_PARAMETER,
287 "GetIfTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
288 apiReturn);
289 apiReturn = gGetIfTable(NULL, &dwSize, FALSE);
290 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
291 "GetIfTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
292 apiReturn);
293 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
294 PMIB_IFTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
295
296 apiReturn = gGetIfTable(buf, &dwSize, FALSE);
297 ok(apiReturn == NO_ERROR,
298 "GetIfTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n\n",
299 apiReturn);
300
301 if (apiReturn == NO_ERROR && winetest_debug > 1)
302 {
303 DWORD i, j;
304 char name[MAX_INTERFACE_NAME_LEN];
305
306 trace( "interface table: %u entries\n", buf->dwNumEntries );
307 for (i = 0; i < buf->dwNumEntries; i++)
308 {
309 MIB_IFROW *row = &buf->table[i];
310 WideCharToMultiByte( CP_ACP, 0, row->wszName, -1, name, MAX_INTERFACE_NAME_LEN, NULL, NULL );
311 trace( "%u: '%s' type %u mtu %u speed %u phys",
312 row->dwIndex, name, row->dwType, row->dwMtu, row->dwSpeed );
313 for (j = 0; j < row->dwPhysAddrLen; j++)
314 printf( " %02x", row->bPhysAddr[j] );
315 printf( "\n" );
316 trace( " in: bytes %u upkts %u nupkts %u disc %u err %u unk %u\n",
317 row->dwInOctets, row->dwInUcastPkts, row->dwInNUcastPkts,
318 row->dwInDiscards, row->dwInErrors, row->dwInUnknownProtos );
319 trace( " out: bytes %u upkts %u nupkts %u disc %u err %u\n",
320 row->dwOutOctets, row->dwOutUcastPkts, row->dwOutNUcastPkts,
321 row->dwOutDiscards, row->dwOutErrors );
322 }
323 }
324 HeapFree(GetProcessHeap(), 0, buf);
325 }
326 }
327 }
328
329 static void testGetIpForwardTable(void)
330 {
331 if (gGetIpForwardTable) {
332 DWORD apiReturn;
333 ULONG dwSize = 0;
334
335 apiReturn = gGetIpForwardTable(NULL, NULL, FALSE);
336 if (apiReturn == ERROR_NOT_SUPPORTED) {
337 skip("GetIpForwardTable is not supported\n");
338 return;
339 }
340 ok(apiReturn == ERROR_INVALID_PARAMETER,
341 "GetIpForwardTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
342 apiReturn);
343 apiReturn = gGetIpForwardTable(NULL, &dwSize, FALSE);
344 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
345 "GetIpForwardTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
346 apiReturn);
347 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
348 PMIB_IPFORWARDTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
349
350 apiReturn = gGetIpForwardTable(buf, &dwSize, FALSE);
351 ok(apiReturn == NO_ERROR,
352 "GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
353 apiReturn);
354
355 if (apiReturn == NO_ERROR && winetest_debug > 1)
356 {
357 DWORD i;
358
359 trace( "IP forward table: %u entries\n", buf->dwNumEntries );
360 for (i = 0; i < buf->dwNumEntries; i++)
361 {
362 char buffer[40];
363 sprintf( buffer, "dest %s", ntoa( buf->table[i].dwForwardDest ));
364 sprintf( buffer + strlen(buffer), " mask %s", ntoa( buf->table[i].dwForwardMask ));
365 trace( "%u: %s gw %s if %u type %u\n", i, buffer,
366 ntoa( buf->table[i].dwForwardNextHop ),
367 buf->table[i].dwForwardIfIndex, buf->table[i].dwForwardType );
368 }
369 }
370 HeapFree(GetProcessHeap(), 0, buf);
371 }
372 }
373 }
374
375 static void testGetIpNetTable(void)
376 {
377 if (gGetIpNetTable) {
378 DWORD apiReturn;
379 ULONG dwSize = 0;
380
381 apiReturn = gGetIpNetTable(NULL, NULL, FALSE);
382 if (apiReturn == ERROR_NOT_SUPPORTED) {
383 skip("GetIpNetTable is not supported\n");
384 return;
385 }
386 ok(apiReturn == ERROR_INVALID_PARAMETER,
387 "GetIpNetTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
388 apiReturn);
389 apiReturn = gGetIpNetTable(NULL, &dwSize, FALSE);
390 ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_INSUFFICIENT_BUFFER,
391 "GetIpNetTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_NO_DATA or ERROR_INSUFFICIENT_BUFFER\n",
392 apiReturn);
393 if (apiReturn == ERROR_NO_DATA)
394 ; /* empty ARP table's okay */
395 else if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
396 PMIB_IPNETTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
397
398 apiReturn = gGetIpNetTable(buf, &dwSize, FALSE);
399 ok(apiReturn == NO_ERROR ||
400 apiReturn == ERROR_NO_DATA, /* empty ARP table's okay */
401 "GetIpNetTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
402 apiReturn);
403
404 if (apiReturn == NO_ERROR && winetest_debug > 1)
405 {
406 DWORD i, j;
407
408 trace( "IP net table: %u entries\n", buf->dwNumEntries );
409 for (i = 0; i < buf->dwNumEntries; i++)
410 {
411 trace( "%u: idx %u type %u addr %s phys",
412 i, buf->table[i].dwIndex, buf->table[i].dwType, ntoa( buf->table[i].dwAddr ));
413 for (j = 0; j < buf->table[i].dwPhysAddrLen; j++)
414 printf( " %02x", buf->table[i].bPhysAddr[j] );
415 printf( "\n" );
416 }
417 }
418 HeapFree(GetProcessHeap(), 0, buf);
419 }
420 }
421 }
422
423 static void testGetIcmpStatistics(void)
424 {
425 if (gGetIcmpStatistics) {
426 DWORD apiReturn;
427 MIB_ICMP stats;
428
429 /* Crashes on Vista */
430 if (0) {
431 apiReturn = gGetIcmpStatistics(NULL);
432 if (apiReturn == ERROR_NOT_SUPPORTED)
433 return;
434 ok(apiReturn == ERROR_INVALID_PARAMETER,
435 "GetIcmpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
436 apiReturn);
437 }
438
439 apiReturn = gGetIcmpStatistics(&stats);
440 if (apiReturn == ERROR_NOT_SUPPORTED)
441 {
442 skip("GetIcmpStatistics is not supported\n");
443 return;
444 }
445 ok(apiReturn == NO_ERROR,
446 "GetIcmpStatistics returned %d, expected NO_ERROR\n", apiReturn);
447 if (apiReturn == NO_ERROR && winetest_debug > 1)
448 {
449 trace( "ICMP stats: %8s %8s\n", "in", "out" );
450 trace( " dwMsgs: %8u %8u\n", stats.stats.icmpInStats.dwMsgs, stats.stats.icmpOutStats.dwMsgs );
451 trace( " dwErrors: %8u %8u\n", stats.stats.icmpInStats.dwErrors, stats.stats.icmpOutStats.dwErrors );
452 trace( " dwDestUnreachs: %8u %8u\n", stats.stats.icmpInStats.dwDestUnreachs, stats.stats.icmpOutStats.dwDestUnreachs );
453 trace( " dwTimeExcds: %8u %8u\n", stats.stats.icmpInStats.dwTimeExcds, stats.stats.icmpOutStats.dwTimeExcds );
454 trace( " dwParmProbs: %8u %8u\n", stats.stats.icmpInStats.dwParmProbs, stats.stats.icmpOutStats.dwParmProbs );
455 trace( " dwSrcQuenchs: %8u %8u\n", stats.stats.icmpInStats.dwSrcQuenchs, stats.stats.icmpOutStats.dwSrcQuenchs );
456 trace( " dwRedirects: %8u %8u\n", stats.stats.icmpInStats.dwRedirects, stats.stats.icmpOutStats.dwRedirects );
457 trace( " dwEchos: %8u %8u\n", stats.stats.icmpInStats.dwEchos, stats.stats.icmpOutStats.dwEchos );
458 trace( " dwEchoReps: %8u %8u\n", stats.stats.icmpInStats.dwEchoReps, stats.stats.icmpOutStats.dwEchoReps );
459 trace( " dwTimestamps: %8u %8u\n", stats.stats.icmpInStats.dwTimestamps, stats.stats.icmpOutStats.dwTimestamps );
460 trace( " dwTimestampReps: %8u %8u\n", stats.stats.icmpInStats.dwTimestampReps, stats.stats.icmpOutStats.dwTimestampReps );
461 trace( " dwAddrMasks: %8u %8u\n", stats.stats.icmpInStats.dwAddrMasks, stats.stats.icmpOutStats.dwAddrMasks );
462 trace( " dwAddrMaskReps: %8u %8u\n", stats.stats.icmpInStats.dwAddrMaskReps, stats.stats.icmpOutStats.dwAddrMaskReps );
463 }
464 }
465 }
466
467 static void testGetIpStatistics(void)
468 {
469 if (gGetIpStatistics) {
470 DWORD apiReturn;
471 MIB_IPSTATS stats;
472
473 apiReturn = gGetIpStatistics(NULL);
474 if (apiReturn == ERROR_NOT_SUPPORTED) {
475 skip("GetIpStatistics is not supported\n");
476 return;
477 }
478 ok(apiReturn == ERROR_INVALID_PARAMETER,
479 "GetIpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
480 apiReturn);
481 apiReturn = gGetIpStatistics(&stats);
482 ok(apiReturn == NO_ERROR,
483 "GetIpStatistics returned %d, expected NO_ERROR\n", apiReturn);
484 if (apiReturn == NO_ERROR && winetest_debug > 1)
485 {
486 trace( "IP stats:\n" );
487 trace( " dwForwarding: %u\n", stats.dwForwarding );
488 trace( " dwDefaultTTL: %u\n", stats.dwDefaultTTL );
489 trace( " dwInReceives: %u\n", stats.dwInReceives );
490 trace( " dwInHdrErrors: %u\n", stats.dwInHdrErrors );
491 trace( " dwInAddrErrors: %u\n", stats.dwInAddrErrors );
492 trace( " dwForwDatagrams: %u\n", stats.dwForwDatagrams );
493 trace( " dwInUnknownProtos: %u\n", stats.dwInUnknownProtos );
494 trace( " dwInDiscards: %u\n", stats.dwInDiscards );
495 trace( " dwInDelivers: %u\n", stats.dwInDelivers );
496 trace( " dwOutRequests: %u\n", stats.dwOutRequests );
497 trace( " dwRoutingDiscards: %u\n", stats.dwRoutingDiscards );
498 trace( " dwOutDiscards: %u\n", stats.dwOutDiscards );
499 trace( " dwOutNoRoutes: %u\n", stats.dwOutNoRoutes );
500 trace( " dwReasmTimeout: %u\n", stats.dwReasmTimeout );
501 trace( " dwReasmReqds: %u\n", stats.dwReasmReqds );
502 trace( " dwReasmOks: %u\n", stats.dwReasmOks );
503 trace( " dwReasmFails: %u\n", stats.dwReasmFails );
504 trace( " dwFragOks: %u\n", stats.dwFragOks );
505 trace( " dwFragFails: %u\n", stats.dwFragFails );
506 trace( " dwFragCreates: %u\n", stats.dwFragCreates );
507 trace( " dwNumIf: %u\n", stats.dwNumIf );
508 trace( " dwNumAddr: %u\n", stats.dwNumAddr );
509 trace( " dwNumRoutes: %u\n", stats.dwNumRoutes );
510 }
511 }
512 }
513
514 static void testGetTcpStatistics(void)
515 {
516 if (gGetTcpStatistics) {
517 DWORD apiReturn;
518 MIB_TCPSTATS stats;
519
520 apiReturn = gGetTcpStatistics(NULL);
521 if (apiReturn == ERROR_NOT_SUPPORTED) {
522 skip("GetTcpStatistics is not supported\n");
523 return;
524 }
525 ok(apiReturn == ERROR_INVALID_PARAMETER,
526 "GetTcpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
527 apiReturn);
528 apiReturn = gGetTcpStatistics(&stats);
529 ok(apiReturn == NO_ERROR,
530 "GetTcpStatistics returned %d, expected NO_ERROR\n", apiReturn);
531 if (apiReturn == NO_ERROR && winetest_debug > 1)
532 {
533 trace( "TCP stats:\n" );
534 trace( " dwRtoAlgorithm: %u\n", stats.dwRtoAlgorithm );
535 trace( " dwRtoMin: %u\n", stats.dwRtoMin );
536 trace( " dwRtoMax: %u\n", stats.dwRtoMax );
537 trace( " dwMaxConn: %u\n", stats.dwMaxConn );
538 trace( " dwActiveOpens: %u\n", stats.dwActiveOpens );
539 trace( " dwPassiveOpens: %u\n", stats.dwPassiveOpens );
540 trace( " dwAttemptFails: %u\n", stats.dwAttemptFails );
541 trace( " dwEstabResets: %u\n", stats.dwEstabResets );
542 trace( " dwCurrEstab: %u\n", stats.dwCurrEstab );
543 trace( " dwInSegs: %u\n", stats.dwInSegs );
544 trace( " dwOutSegs: %u\n", stats.dwOutSegs );
545 trace( " dwRetransSegs: %u\n", stats.dwRetransSegs );
546 trace( " dwInErrs: %u\n", stats.dwInErrs );
547 trace( " dwOutRsts: %u\n", stats.dwOutRsts );
548 trace( " dwNumConns: %u\n", stats.dwNumConns );
549 }
550 }
551 }
552
553 static void testGetUdpStatistics(void)
554 {
555 if (gGetUdpStatistics) {
556 DWORD apiReturn;
557 MIB_UDPSTATS stats;
558
559 apiReturn = gGetUdpStatistics(NULL);
560 if (apiReturn == ERROR_NOT_SUPPORTED) {
561 skip("GetUdpStatistics is not supported\n");
562 return;
563 }
564 ok(apiReturn == ERROR_INVALID_PARAMETER,
565 "GetUdpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
566 apiReturn);
567 apiReturn = gGetUdpStatistics(&stats);
568 ok(apiReturn == NO_ERROR,
569 "GetUdpStatistics returned %d, expected NO_ERROR\n", apiReturn);
570 if (apiReturn == NO_ERROR && winetest_debug > 1)
571 {
572 trace( "UDP stats:\n" );
573 trace( " dwInDatagrams: %u\n", stats.dwInDatagrams );
574 trace( " dwNoPorts: %u\n", stats.dwNoPorts );
575 trace( " dwInErrors: %u\n", stats.dwInErrors );
576 trace( " dwOutDatagrams: %u\n", stats.dwOutDatagrams );
577 trace( " dwNumAddrs: %u\n", stats.dwNumAddrs );
578 }
579 }
580 }
581
582 static void testGetTcpTable(void)
583 {
584 if (gGetTcpTable) {
585 DWORD apiReturn;
586 ULONG dwSize = 0;
587
588 apiReturn = gGetTcpTable(NULL, &dwSize, FALSE);
589 if (apiReturn == ERROR_NOT_SUPPORTED) {
590 skip("GetTcpTable is not supported\n");
591 return;
592 }
593 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER ||
594 broken(apiReturn == ERROR_NO_DATA), /* win95 */
595 "GetTcpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
596 apiReturn);
597 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
598 PMIB_TCPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
599
600 apiReturn = gGetTcpTable(buf, &dwSize, FALSE);
601 ok(apiReturn == NO_ERROR,
602 "GetTcpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
603 apiReturn);
604
605 if (apiReturn == NO_ERROR && winetest_debug > 1)
606 {
607 DWORD i;
608 trace( "TCP table: %u entries\n", buf->dwNumEntries );
609 for (i = 0; i < buf->dwNumEntries; i++)
610 {
611 char buffer[40];
612 sprintf( buffer, "local %s:%u",
613 ntoa(buf->table[i].dwLocalAddr), ntohs(buf->table[i].dwLocalPort) );
614 trace( "%u: %s remote %s:%u state %u\n",
615 i, buffer, ntoa( buf->table[i].dwRemoteAddr ),
616 ntohs(buf->table[i].dwRemotePort), buf->table[i].dwState );
617 }
618 }
619 HeapFree(GetProcessHeap(), 0, buf);
620 }
621 }
622 }
623
624 static void testGetUdpTable(void)
625 {
626 if (gGetUdpTable) {
627 DWORD apiReturn;
628 ULONG dwSize = 0;
629
630 apiReturn = gGetUdpTable(NULL, &dwSize, FALSE);
631 if (apiReturn == ERROR_NOT_SUPPORTED) {
632 skip("GetUdpTable is not supported\n");
633 return;
634 }
635 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
636 "GetUdpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
637 apiReturn);
638 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
639 PMIB_UDPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
640
641 apiReturn = gGetUdpTable(buf, &dwSize, FALSE);
642 ok(apiReturn == NO_ERROR,
643 "GetUdpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
644 apiReturn);
645
646 if (apiReturn == NO_ERROR && winetest_debug > 1)
647 {
648 DWORD i;
649 trace( "UDP table: %u entries\n", buf->dwNumEntries );
650 for (i = 0; i < buf->dwNumEntries; i++)
651 trace( "%u: %s:%u\n",
652 i, ntoa( buf->table[i].dwLocalAddr ), ntohs(buf->table[i].dwLocalPort) );
653 }
654 HeapFree(GetProcessHeap(), 0, buf);
655 }
656 }
657 }
658
659 /*
660 still-to-be-tested NT4-onward functions:
661 CreateIpForwardEntry
662 DeleteIpForwardEntry
663 CreateIpNetEntry
664 DeleteIpNetEntry
665 GetFriendlyIfIndex
666 GetRTTAndHopCount
667 SetIfEntry
668 SetIpForwardEntry
669 SetIpNetEntry
670 SetIpStatistics
671 SetIpTTL
672 SetTcpEntry
673 */
674 static void testWinNT4Functions(void)
675 {
676 testGetNumberOfInterfaces();
677 testGetIpAddrTable();
678 testGetIfTable();
679 testGetIpForwardTable();
680 testGetIpNetTable();
681 testGetIcmpStatistics();
682 testGetIpStatistics();
683 testGetTcpStatistics();
684 testGetUdpStatistics();
685 testGetTcpTable();
686 testGetUdpTable();
687 }
688
689 static void testGetInterfaceInfo(void)
690 {
691 if (gGetInterfaceInfo) {
692 DWORD apiReturn;
693 ULONG len = 0;
694
695 apiReturn = gGetInterfaceInfo(NULL, NULL);
696 if (apiReturn == ERROR_NOT_SUPPORTED) {
697 skip("GetInterfaceInfo is not supported\n");
698 return;
699 }
700 ok(apiReturn == ERROR_INVALID_PARAMETER,
701 "GetInterfaceInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
702 apiReturn);
703 apiReturn = gGetInterfaceInfo(NULL, &len);
704 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
705 "GetInterfaceInfo returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
706 apiReturn);
707 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
708 PIP_INTERFACE_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
709
710 apiReturn = gGetInterfaceInfo(buf, &len);
711 ok(apiReturn == NO_ERROR,
712 "GetInterfaceInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
713 apiReturn);
714 HeapFree(GetProcessHeap(), 0, buf);
715 }
716 }
717 }
718
719 static void testGetAdaptersInfo(void)
720 {
721 if (gGetAdaptersInfo) {
722 DWORD apiReturn;
723 ULONG len = 0;
724
725 apiReturn = gGetAdaptersInfo(NULL, NULL);
726 if (apiReturn == ERROR_NOT_SUPPORTED) {
727 skip("GetAdaptersInfo is not supported\n");
728 return;
729 }
730 ok(apiReturn == ERROR_INVALID_PARAMETER,
731 "GetAdaptersInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
732 apiReturn);
733 apiReturn = gGetAdaptersInfo(NULL, &len);
734 ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_BUFFER_OVERFLOW,
735 "GetAdaptersInfo returned %d, expected ERROR_NO_DATA or ERROR_BUFFER_OVERFLOW\n",
736 apiReturn);
737 if (apiReturn == ERROR_NO_DATA)
738 ; /* no adapter's, that's okay */
739 else if (apiReturn == ERROR_BUFFER_OVERFLOW) {
740 PIP_ADAPTER_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
741
742 apiReturn = gGetAdaptersInfo(buf, &len);
743 ok(apiReturn == NO_ERROR,
744 "GetAdaptersInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
745 apiReturn);
746 HeapFree(GetProcessHeap(), 0, buf);
747 }
748 }
749 }
750
751 static void testGetNetworkParams(void)
752 {
753 if (gGetNetworkParams) {
754 DWORD apiReturn;
755 ULONG len = 0;
756
757 apiReturn = gGetNetworkParams(NULL, NULL);
758 if (apiReturn == ERROR_NOT_SUPPORTED) {
759 skip("GetNetworkParams is not supported\n");
760 return;
761 }
762 ok(apiReturn == ERROR_INVALID_PARAMETER,
763 "GetNetworkParams returned %d, expected ERROR_INVALID_PARAMETER\n",
764 apiReturn);
765 apiReturn = gGetNetworkParams(NULL, &len);
766 ok(apiReturn == ERROR_BUFFER_OVERFLOW,
767 "GetNetworkParams returned %d, expected ERROR_BUFFER_OVERFLOW\n",
768 apiReturn);
769 if (apiReturn == ERROR_BUFFER_OVERFLOW) {
770 PFIXED_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
771
772 apiReturn = gGetNetworkParams(buf, &len);
773 ok(apiReturn == NO_ERROR,
774 "GetNetworkParams(buf, &dwSize) returned %d, expected NO_ERROR\n",
775 apiReturn);
776 HeapFree(GetProcessHeap(), 0, buf);
777 }
778 }
779 }
780
781 /*
782 still-to-be-tested 98-onward functions:
783 GetBestInterface
784 GetBestRoute
785 IpReleaseAddress
786 IpRenewAddress
787 */
788 static DWORD CALLBACK testWin98Functions(void *p)
789 {
790 testGetInterfaceInfo();
791 testGetAdaptersInfo();
792 testGetNetworkParams();
793 return 0;
794 }
795
796 static void testGetPerAdapterInfo(void)
797 {
798 DWORD ret, needed;
799 void *buffer;
800
801 if (!gGetPerAdapterInfo) return;
802 ret = gGetPerAdapterInfo(1, NULL, NULL);
803 if (ret == ERROR_NOT_SUPPORTED) {
804 skip("GetPerAdapterInfo is not supported\n");
805 return;
806 }
807 ok( ret == ERROR_INVALID_PARAMETER, "got %u instead of ERROR_INVALID_PARAMETER\n", ret );
808 needed = 0xdeadbeef;
809 ret = gGetPerAdapterInfo(1, NULL, &needed);
810 if (ret == ERROR_NO_DATA) return; /* no such adapter */
811 ok( ret == ERROR_BUFFER_OVERFLOW, "got %u instead of ERROR_BUFFER_OVERFLOW\n", ret );
812 ok( needed != 0xdeadbeef, "needed not set\n" );
813 buffer = HeapAlloc( GetProcessHeap(), 0, needed );
814 ret = gGetPerAdapterInfo(1, buffer, &needed);
815 ok( ret == NO_ERROR, "got %u instead of NO_ERROR\n", ret );
816 HeapFree( GetProcessHeap(), 0, buffer );
817 }
818
819 static void testNotifyAddrChange(void)
820 {
821 DWORD ret, bytes;
822 OVERLAPPED overlapped;
823 HANDLE handle;
824 BOOL success;
825
826 if (!gNotifyAddrChange)
827 {
828 win_skip("NotifyAddrChange not present\n");
829 return;
830 }
831 if (!gCancelIPChangeNotify)
832 {
833 win_skip("CancelIPChangeNotify not present\n");
834 return;
835 }
836
837 handle = NULL;
838 ZeroMemory(&overlapped, sizeof(overlapped));
839 ret = gNotifyAddrChange(&handle, &overlapped);
840 if (ret == ERROR_NOT_SUPPORTED)
841 {
842 win_skip("NotifyAddrChange is not supported\n");
843 return;
844 }
845 ok(ret == ERROR_IO_PENDING, "NotifyAddrChange returned %d, expected ERROR_IO_PENDING\n", ret);
846 ret = GetLastError();
847 todo_wine ok(ret == ERROR_IO_PENDING, "GetLastError returned %d, expected ERROR_IO_PENDING\n", ret);
848 success = gCancelIPChangeNotify(&overlapped);
849 todo_wine ok(success == TRUE, "CancelIPChangeNotify returned FALSE, expected TRUE\n");
850
851 ZeroMemory(&overlapped, sizeof(overlapped));
852 success = gCancelIPChangeNotify(&overlapped);
853 ok(success == FALSE, "CancelIPChangeNotify returned TRUE, expected FALSE\n");
854
855 handle = NULL;
856 ZeroMemory(&overlapped, sizeof(overlapped));
857 overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
858 ret = gNotifyAddrChange(&handle, &overlapped);
859 ok(ret == ERROR_IO_PENDING, "NotifyAddrChange returned %d, expected ERROR_IO_PENDING\n", ret);
860 todo_wine ok(handle != INVALID_HANDLE_VALUE, "NotifyAddrChange returned invalid file handle\n");
861 success = GetOverlappedResult(handle, &overlapped, &bytes, FALSE);
862 ok(success == FALSE, "GetOverlappedResult returned TRUE, expected FALSE\n");
863 ret = GetLastError();
864 ok(ret == ERROR_IO_INCOMPLETE, "GetLastError returned %d, expected ERROR_IO_INCOMPLETE\n", ret);
865 success = gCancelIPChangeNotify(&overlapped);
866 todo_wine ok(success == TRUE, "CancelIPChangeNotify returned FALSE, expected TRUE\n");
867
868 if (winetest_interactive)
869 {
870 handle = NULL;
871 ZeroMemory(&overlapped, sizeof(overlapped));
872 overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
873 trace("Testing asynchronous ipv4 address change notification. Please "
874 "change the ipv4 address of one of your network interfaces\n");
875 ret = gNotifyAddrChange(&handle, &overlapped);
876 ok(ret == ERROR_IO_PENDING, "NotifyAddrChange returned %d, expected NO_ERROR\n", ret);
877 success = GetOverlappedResult(handle, &overlapped, &bytes, TRUE);
878 ok(success == TRUE, "GetOverlappedResult returned FALSE, expected TRUE\n");
879 }
880
881 /* test synchronous functionality */
882 if (winetest_interactive)
883 {
884 trace("Testing synchronous ipv4 address change notification. Please "
885 "change the ipv4 address of one of your network interfaces\n");
886 ret = gNotifyAddrChange(NULL, NULL);
887 todo_wine ok(ret == NO_ERROR, "NotifyAddrChange returned %d, expected NO_ERROR\n", ret);
888 }
889 }
890
891 /*
892 still-to-be-tested 2K-onward functions:
893 AddIPAddress
894 CreateProxyArpEntry
895 DeleteIPAddress
896 DeleteProxyArpEntry
897 EnableRouter
898 FlushIpNetTable
899 GetAdapterIndex
900 NotifyRouteChange + CancelIPChangeNotify
901 SendARP
902 UnenableRouter
903 */
904 static void testWin2KFunctions(void)
905 {
906 testGetPerAdapterInfo();
907 testNotifyAddrChange();
908 }
909
910 static void test_GetAdaptersAddresses(void)
911 {
912 ULONG ret, size;
913 IP_ADAPTER_ADDRESSES *aa, *ptr;
914 IP_ADAPTER_UNICAST_ADDRESS *ua;
915
916 if (!gGetAdaptersAddresses)
917 {
918 win_skip("GetAdaptersAddresses not present\n");
919 return;
920 }
921
922 ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, NULL);
923 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", ret);
924
925 /* size should be ignored and overwritten if buffer is NULL */
926 size = 0x7fffffff;
927 ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
928 ok(ret == ERROR_BUFFER_OVERFLOW, "expected ERROR_BUFFER_OVERFLOW, got %u\n", ret);
929 if (ret != ERROR_BUFFER_OVERFLOW) return;
930
931 ptr = HeapAlloc(GetProcessHeap(), 0, size);
932 ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, ptr, &size);
933 ok(!ret, "expected ERROR_SUCCESS got %u\n", ret);
934
935 for (aa = ptr; !ret && aa; aa = aa->Next)
936 {
937 ok(aa->DnsSuffix != NULL, "DnsSuffix is not a valid pointer\n");
938 ok(aa->Description != NULL, "Description is not a valid pointer\n");
939 ok(aa->FriendlyName != NULL, "FriendlyName is not a valid pointer\n");
940
941 if (winetest_debug <= 1)
942 continue;
943
944 trace("Length: %u\n", S(U(*aa)).Length);
945 trace("IfIndex: %u\n", S(U(*aa)).IfIndex);
946 trace("Next: %p\n", aa->Next);
947 trace("AdapterName: %s\n", aa->AdapterName);
948 trace("FirstUnicastAddress: %p\n", aa->FirstUnicastAddress);
949 ua = aa->FirstUnicastAddress;
950 while (ua)
951 {
952 trace("\tLength: %u\n", S(U(*ua)).Length);
953 trace("\tFlags: 0x%08x\n", S(U(*ua)).Flags);
954 trace("\tNext: %p\n", ua->Next);
955 trace("\tAddress.lpSockaddr: %p\n", ua->Address.lpSockaddr);
956 trace("\tAddress.iSockaddrLength: %d\n", ua->Address.iSockaddrLength);
957 trace("\tPrefixOrigin: %u\n", ua->PrefixOrigin);
958 trace("\tSuffixOrigin: %u\n", ua->SuffixOrigin);
959 trace("\tDadState: %u\n", ua->DadState);
960 trace("\tValidLifetime: 0x%08x\n", ua->ValidLifetime);
961 trace("\tPreferredLifetime: 0x%08x\n", ua->PreferredLifetime);
962 trace("\tLeaseLifetime: 0x%08x\n", ua->LeaseLifetime);
963 trace("\n");
964 ua = ua->Next;
965 }
966 trace("FirstAnycastAddress: %p\n", aa->FirstAnycastAddress);
967 trace("FirstMulticastAddress: %p\n", aa->FirstMulticastAddress);
968 trace("FirstDnsServerAddress: %p\n", aa->FirstDnsServerAddress);
969 trace("DnsSuffix: %p\n", aa->DnsSuffix);
970 trace("Description: %p\n", aa->Description);
971 trace("FriendlyName: %p\n", aa->FriendlyName);
972 trace("PhysicalAddress: %02x\n", aa->PhysicalAddress[0]);
973 trace("PhysicalAddressLength: %u\n", aa->PhysicalAddressLength);
974 trace("Flags: 0x%08x\n", aa->Flags);
975 trace("Mtu: %u\n", aa->Mtu);
976 trace("IfType: %u\n", aa->IfType);
977 trace("OperStatus: %u\n", aa->OperStatus);
978 trace("\n");
979 }
980 HeapFree(GetProcessHeap(), 0, ptr);
981 }
982
983 START_TEST(iphlpapi)
984 {
985
986 loadIPHlpApi();
987 if (hLibrary) {
988 HANDLE thread;
989
990 testWin98OnlyFunctions();
991 testWinNT4Functions();
992
993 /* run testGetXXXX in two threads at once to make sure we don't crash in that case */
994 thread = CreateThread(NULL, 0, testWin98Functions, NULL, 0, NULL);
995 testWin98Functions(NULL);
996 WaitForSingleObject(thread, INFINITE);
997
998 testWin2KFunctions();
999 test_GetAdaptersAddresses();
1000 freeIPHlpApi();
1001 }
1002 }