include: Add missing local attributes to shobjidl.idl.
[wine] / dlls / iphlpapi / tests / 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 "windef.h"
39 #include "winbase.h"
40 #include "iphlpapi.h"
41 #include "iprtrmib.h"
42 #include "wine/test.h"
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 static HMODULE hLibrary = NULL;
47
48 typedef DWORD (WINAPI *GetNumberOfInterfacesFunc)(PDWORD);
49 typedef DWORD (WINAPI *GetIpAddrTableFunc)(PMIB_IPADDRTABLE,PULONG,BOOL);
50 typedef DWORD (WINAPI *GetIfEntryFunc)(PMIB_IFROW);
51 typedef DWORD (WINAPI *GetFriendlyIfIndexFunc)(DWORD);
52 typedef DWORD (WINAPI *GetIfTableFunc)(PMIB_IFTABLE,PULONG,BOOL);
53 typedef DWORD (WINAPI *GetIpForwardTableFunc)(PMIB_IPFORWARDTABLE,PULONG,BOOL);
54 typedef DWORD (WINAPI *GetIpNetTableFunc)(PMIB_IPNETTABLE,PULONG,BOOL);
55 typedef DWORD (WINAPI *GetInterfaceInfoFunc)(PIP_INTERFACE_INFO,PULONG);
56 typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO,PULONG);
57 typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO,PULONG);
58 typedef DWORD (WINAPI *GetIcmpStatisticsFunc)(PMIB_ICMP);
59 typedef DWORD (WINAPI *GetIpStatisticsFunc)(PMIB_IPSTATS);
60 typedef DWORD (WINAPI *GetTcpStatisticsFunc)(PMIB_TCPSTATS);
61 typedef DWORD (WINAPI *GetUdpStatisticsFunc)(PMIB_UDPSTATS);
62 typedef DWORD (WINAPI *GetTcpTableFunc)(PMIB_TCPTABLE,PDWORD,BOOL);
63 typedef DWORD (WINAPI *GetUdpTableFunc)(PMIB_UDPTABLE,PDWORD,BOOL);
64 typedef DWORD (WINAPI *GetPerAdapterInfoFunc)(ULONG,PIP_PER_ADAPTER_INFO,PULONG);
65
66 static GetNumberOfInterfacesFunc gGetNumberOfInterfaces = NULL;
67 static GetIpAddrTableFunc gGetIpAddrTable = NULL;
68 static GetIfEntryFunc gGetIfEntry = NULL;
69 static GetFriendlyIfIndexFunc gGetFriendlyIfIndex = NULL;
70 static GetIfTableFunc gGetIfTable = NULL;
71 static GetIpForwardTableFunc gGetIpForwardTable = NULL;
72 static GetIpNetTableFunc gGetIpNetTable = NULL;
73 static GetInterfaceInfoFunc gGetInterfaceInfo = NULL;
74 static GetAdaptersInfoFunc gGetAdaptersInfo = NULL;
75 static GetNetworkParamsFunc gGetNetworkParams = NULL;
76 static GetIcmpStatisticsFunc gGetIcmpStatistics = NULL;
77 static GetIpStatisticsFunc gGetIpStatistics = NULL;
78 static GetTcpStatisticsFunc gGetTcpStatistics = NULL;
79 static GetUdpStatisticsFunc gGetUdpStatistics = NULL;
80 static GetTcpTableFunc gGetTcpTable = NULL;
81 static GetUdpTableFunc gGetUdpTable = NULL;
82 static GetPerAdapterInfoFunc gGetPerAdapterInfo = NULL;
83
84 static void loadIPHlpApi(void)
85 {
86   hLibrary = LoadLibraryA("iphlpapi.dll");
87   if (hLibrary) {
88     gGetNumberOfInterfaces = (GetNumberOfInterfacesFunc)GetProcAddress(
89      hLibrary, "GetNumberOfInterfaces");
90     gGetIpAddrTable = (GetIpAddrTableFunc)GetProcAddress(
91      hLibrary, "GetIpAddrTable");
92     gGetIfEntry = (GetIfEntryFunc)GetProcAddress(
93      hLibrary, "GetIfEntry");
94     gGetFriendlyIfIndex = (GetFriendlyIfIndexFunc)GetProcAddress(
95      hLibrary, "GetFriendlyIfIndex");
96     gGetIfTable = (GetIfTableFunc)GetProcAddress(
97      hLibrary, "GetIfTable");
98     gGetIpForwardTable = (GetIpForwardTableFunc)GetProcAddress(
99      hLibrary, "GetIpForwardTable");
100     gGetIpNetTable = (GetIpNetTableFunc)GetProcAddress(
101      hLibrary, "GetIpNetTable");
102     gGetInterfaceInfo = (GetInterfaceInfoFunc)GetProcAddress(
103      hLibrary, "GetInterfaceInfo");
104     gGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress(
105      hLibrary, "GetAdaptersInfo");
106     gGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(
107      hLibrary, "GetNetworkParams");
108     gGetIcmpStatistics = (GetIcmpStatisticsFunc)GetProcAddress(
109      hLibrary, "GetIcmpStatistics");
110     gGetIpStatistics = (GetIpStatisticsFunc)GetProcAddress(
111      hLibrary, "GetIpStatistics");
112     gGetTcpStatistics = (GetTcpStatisticsFunc)GetProcAddress(
113      hLibrary, "GetTcpStatistics");
114     gGetUdpStatistics = (GetUdpStatisticsFunc)GetProcAddress(
115      hLibrary, "GetUdpStatistics");
116     gGetTcpTable = (GetTcpTableFunc)GetProcAddress(
117      hLibrary, "GetTcpTable");
118     gGetUdpTable = (GetUdpTableFunc)GetProcAddress(
119      hLibrary, "GetUdpTable");
120     gGetPerAdapterInfo = (GetPerAdapterInfoFunc)GetProcAddress(hLibrary, "GetPerAdapterInfo");
121   }
122 }
123
124 static void freeIPHlpApi(void)
125 {
126   if (hLibrary) {
127     gGetNumberOfInterfaces = NULL;
128     gGetIpAddrTable = NULL;
129     gGetIfEntry = NULL;
130     gGetFriendlyIfIndex = NULL;
131     gGetIfTable = NULL;
132     gGetIpForwardTable = NULL;
133     gGetIpNetTable = NULL;
134     gGetInterfaceInfo = NULL;
135     gGetAdaptersInfo = NULL;
136     gGetNetworkParams = NULL;
137     gGetIcmpStatistics = NULL;
138     gGetIpStatistics = NULL;
139     gGetTcpStatistics = NULL;
140     gGetUdpStatistics = NULL;
141     gGetTcpTable = NULL;
142     gGetUdpTable = NULL;
143     FreeLibrary(hLibrary);
144     hLibrary = NULL;
145   }
146 }
147
148 /*
149 still-to-be-tested 98-only functions:
150 GetUniDirectionalAdapterInfo
151 */
152 static void testWin98OnlyFunctions(void)
153 {
154 }
155
156 static void testGetNumberOfInterfaces(void)
157 {
158   if (gGetNumberOfInterfaces) {
159     DWORD apiReturn, numInterfaces;
160
161     /* Crashes on Vista */
162     if (0) {
163       apiReturn = gGetNumberOfInterfaces(NULL), numInterfaces;
164       if (apiReturn == ERROR_NOT_SUPPORTED)
165         return;
166       ok(apiReturn == ERROR_INVALID_PARAMETER,
167        "GetNumberOfInterfaces(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
168        apiReturn);
169     }
170
171     apiReturn = gGetNumberOfInterfaces(&numInterfaces);
172     if (apiReturn == ERROR_NOT_SUPPORTED) {
173       skip("GetNumberOfInterfaces is not supported\n");
174       return;
175     }
176     ok(apiReturn == NO_ERROR,
177      "GetNumberOfInterfaces returned %d, expected 0\n", apiReturn);
178   }
179 }
180
181 static void testGetIfEntry(DWORD index)
182 {
183   if (gGetIfEntry) {
184     DWORD apiReturn;
185     MIB_IFROW row;
186
187     memset(&row, 0, sizeof(row));
188     apiReturn = gGetIfEntry(NULL);
189     if (apiReturn == ERROR_NOT_SUPPORTED) {
190       skip("GetIfEntry is not supported\n");
191       return;
192     }
193     ok(apiReturn == ERROR_INVALID_PARAMETER,
194      "GetIfEntry(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
195      apiReturn);
196     row.dwIndex = -1; /* hope that's always bogus! */
197     apiReturn = gGetIfEntry(&row);
198     ok(apiReturn == ERROR_INVALID_DATA ||
199      apiReturn == ERROR_FILE_NOT_FOUND /* Vista */,
200      "GetIfEntry(bogus row) returned %d, expected ERROR_INVALID_DATA or ERROR_FILE_NOT_FOUND\n",
201      apiReturn);
202     row.dwIndex = index;
203     apiReturn = gGetIfEntry(&row);
204     ok(apiReturn == NO_ERROR, 
205      "GetIfEntry returned %d, expected NO_ERROR\n", apiReturn);
206   }
207 }
208
209 static void testGetIpAddrTable(void)
210 {
211   if (gGetIpAddrTable) {
212     DWORD apiReturn;
213     ULONG dwSize = 0;
214
215     apiReturn = gGetIpAddrTable(NULL, NULL, FALSE);
216     if (apiReturn == ERROR_NOT_SUPPORTED) {
217       skip("GetIpAddrTable is not supported\n");
218       return;
219     }
220     ok(apiReturn == ERROR_INVALID_PARAMETER,
221      "GetIpAddrTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
222      apiReturn);
223     apiReturn = gGetIpAddrTable(NULL, &dwSize, FALSE);
224     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
225      "GetIpAddrTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
226      apiReturn);
227     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
228       PMIB_IPADDRTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
229
230       apiReturn = gGetIpAddrTable(buf, &dwSize, FALSE);
231       ok(apiReturn == NO_ERROR,
232        "GetIpAddrTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
233        apiReturn);
234       if (apiReturn == NO_ERROR && buf->dwNumEntries)
235         testGetIfEntry(buf->table[0].dwIndex);
236       HeapFree(GetProcessHeap(), 0, buf);
237     }
238   }
239 }
240
241 static void testGetIfTable(void)
242 {
243   if (gGetIfTable) {
244     DWORD apiReturn;
245     ULONG dwSize = 0;
246
247     apiReturn = gGetIfTable(NULL, NULL, FALSE);
248     if (apiReturn == ERROR_NOT_SUPPORTED) {
249       skip("GetIfTable is not supported\n");
250       return;
251     }
252     ok(apiReturn == ERROR_INVALID_PARAMETER,
253      "GetIfTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
254      apiReturn);
255     apiReturn = gGetIfTable(NULL, &dwSize, FALSE);
256     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
257      "GetIfTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
258      apiReturn);
259     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
260       PMIB_IFTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
261
262       apiReturn = gGetIfTable(buf, &dwSize, FALSE);
263       ok(apiReturn == NO_ERROR,
264        "GetIfTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n\n",
265        apiReturn);
266       HeapFree(GetProcessHeap(), 0, buf);
267     }
268   }
269 }
270
271 static void testGetIpForwardTable(void)
272 {
273   if (gGetIpForwardTable) {
274     DWORD apiReturn;
275     ULONG dwSize = 0;
276
277     apiReturn = gGetIpForwardTable(NULL, NULL, FALSE);
278     if (apiReturn == ERROR_NOT_SUPPORTED) {
279       skip("GetIpForwardTable is not supported\n");
280       return;
281     }
282     ok(apiReturn == ERROR_INVALID_PARAMETER,
283      "GetIpForwardTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
284      apiReturn);
285     apiReturn = gGetIpForwardTable(NULL, &dwSize, FALSE);
286     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
287      "GetIpForwardTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
288      apiReturn);
289     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
290       PMIB_IPFORWARDTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
291
292       apiReturn = gGetIpForwardTable(buf, &dwSize, FALSE);
293       ok(apiReturn == NO_ERROR,
294        "GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
295        apiReturn);
296       HeapFree(GetProcessHeap(), 0, buf);
297     }
298   }
299 }
300
301 static void testGetIpNetTable(void)
302 {
303   if (gGetIpNetTable) {
304     DWORD apiReturn;
305     ULONG dwSize = 0;
306
307     apiReturn = gGetIpNetTable(NULL, NULL, FALSE);
308     if (apiReturn == ERROR_NOT_SUPPORTED) {
309       skip("GetIpNetTable is not supported\n");
310       return;
311     }
312     ok(apiReturn == ERROR_INVALID_PARAMETER,
313      "GetIpNetTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
314      apiReturn);
315     apiReturn = gGetIpNetTable(NULL, &dwSize, FALSE);
316     ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_INSUFFICIENT_BUFFER,
317      "GetIpNetTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_NO_DATA or ERROR_INSUFFICIENT_BUFFER\n",
318      apiReturn);
319     if (apiReturn == ERROR_NO_DATA)
320       ; /* empty ARP table's okay */
321     else if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
322       PMIB_IPNETTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
323
324       apiReturn = gGetIpNetTable(buf, &dwSize, FALSE);
325       ok(apiReturn == NO_ERROR ||
326          apiReturn == ERROR_NO_DATA, /* empty ARP table's okay */
327        "GetIpNetTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
328        apiReturn);
329       HeapFree(GetProcessHeap(), 0, buf);
330     }
331   }
332 }
333
334 static void testGetIcmpStatistics(void)
335 {
336   if (gGetIcmpStatistics) {
337     DWORD apiReturn;
338     MIB_ICMP stats;
339
340     /* Crashes on Vista */
341     if (0) {
342       apiReturn = gGetIcmpStatistics(NULL);
343       if (apiReturn == ERROR_NOT_SUPPORTED)
344         return;
345       ok(apiReturn == ERROR_INVALID_PARAMETER,
346        "GetIcmpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
347        apiReturn);
348     }
349
350     apiReturn = gGetIcmpStatistics(&stats);
351     if (apiReturn == ERROR_NOT_SUPPORTED)
352     {
353       skip("GetIcmpStatistics is not supported\n");
354       return;
355     }
356     ok(apiReturn == NO_ERROR,
357      "GetIcmpStatistics returned %d, expected NO_ERROR\n", apiReturn);
358   }
359 }
360
361 static void testGetIpStatistics(void)
362 {
363   if (gGetIpStatistics) {
364     DWORD apiReturn;
365     MIB_IPSTATS stats;
366
367     apiReturn = gGetIpStatistics(NULL);
368     if (apiReturn == ERROR_NOT_SUPPORTED) {
369       skip("GetIpStatistics is not supported\n");
370       return;
371     }
372     ok(apiReturn == ERROR_INVALID_PARAMETER,
373      "GetIpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
374      apiReturn);
375     apiReturn = gGetIpStatistics(&stats);
376     ok(apiReturn == NO_ERROR,
377       "GetIpStatistics returned %d, expected NO_ERROR\n", apiReturn);
378   }
379 }
380
381 static void testGetTcpStatistics(void)
382 {
383   if (gGetTcpStatistics) {
384     DWORD apiReturn;
385     MIB_TCPSTATS stats;
386
387     apiReturn = gGetTcpStatistics(NULL);
388     if (apiReturn == ERROR_NOT_SUPPORTED) {
389       skip("GetTcpStatistics is not supported\n");
390       return;
391     }
392     ok(apiReturn == ERROR_INVALID_PARAMETER,
393      "GetTcpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
394      apiReturn);
395     apiReturn = gGetTcpStatistics(&stats);
396     ok(apiReturn == NO_ERROR,
397       "GetTcpStatistics returned %d, expected NO_ERROR\n", apiReturn);
398   }
399 }
400
401 static void testGetUdpStatistics(void)
402 {
403   if (gGetUdpStatistics) {
404     DWORD apiReturn;
405     MIB_UDPSTATS stats;
406
407     apiReturn = gGetUdpStatistics(NULL);
408     if (apiReturn == ERROR_NOT_SUPPORTED) {
409       skip("GetUdpStatistics is not supported\n");
410       return;
411     }
412     ok(apiReturn == ERROR_INVALID_PARAMETER,
413      "GetUdpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
414      apiReturn);
415     apiReturn = gGetUdpStatistics(&stats);
416     ok(apiReturn == NO_ERROR,
417      "GetUdpStatistics returned %d, expected NO_ERROR\n", apiReturn);
418   }
419 }
420
421 static void testGetTcpTable(void)
422 {
423   if (gGetTcpTable) {
424     DWORD apiReturn;
425     ULONG dwSize = 0;
426
427     apiReturn = gGetTcpTable(NULL, NULL, FALSE);
428     if (apiReturn == ERROR_NOT_SUPPORTED) {
429       skip("GetTcpTable is not supported\n");
430       return;
431     }
432     ok(apiReturn == ERROR_INVALID_PARAMETER,
433      "GetTcpTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
434      apiReturn);
435     apiReturn = gGetTcpTable(NULL, &dwSize, FALSE);
436     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER ||
437        broken(apiReturn == ERROR_NO_DATA), /* win95 */
438      "GetTcpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
439      apiReturn);
440     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
441       PMIB_TCPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
442
443       apiReturn = gGetTcpTable(buf, &dwSize, FALSE);
444       ok(apiReturn == NO_ERROR,
445        "GetTcpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
446        apiReturn);
447       HeapFree(GetProcessHeap(), 0, buf);
448     }
449   }
450 }
451
452 static void testGetUdpTable(void)
453 {
454   if (gGetUdpTable) {
455     DWORD apiReturn;
456     ULONG dwSize = 0;
457
458     apiReturn = gGetUdpTable(NULL, NULL, FALSE);
459     if (apiReturn == ERROR_NOT_SUPPORTED) {
460       skip("GetUdpTable is not supported\n");
461       return;
462     }
463     ok(apiReturn == ERROR_INVALID_PARAMETER,
464      "GetUdpTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
465      apiReturn);
466     apiReturn = gGetUdpTable(NULL, &dwSize, FALSE);
467     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
468      "GetUdpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
469      apiReturn);
470     if (apiReturn != ERROR_INSUFFICIENT_BUFFER) {
471       PMIB_UDPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
472
473       apiReturn = gGetUdpTable(buf, &dwSize, FALSE);
474       ok(apiReturn == NO_ERROR,
475        "GetUdpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
476        apiReturn);
477       HeapFree(GetProcessHeap(), 0, buf);
478     }
479   }
480 }
481
482 /*
483 still-to-be-tested NT4-onward functions:
484 CreateIpForwardEntry
485 DeleteIpForwardEntry
486 CreateIpNetEntry
487 DeleteIpNetEntry
488 GetFriendlyIfIndex
489 GetRTTAndHopCount
490 SetIfEntry
491 SetIpForwardEntry
492 SetIpNetEntry
493 SetIpStatistics
494 SetIpTTL
495 SetTcpEntry
496 */
497 static void testWinNT4Functions(void)
498 {
499   testGetNumberOfInterfaces();
500   testGetIpAddrTable();
501   testGetIfTable();
502   testGetIpForwardTable();
503   testGetIpNetTable();
504   testGetIcmpStatistics();
505   testGetIpStatistics();
506   testGetTcpStatistics();
507   testGetUdpStatistics();
508   testGetTcpTable();
509   testGetUdpTable();
510 }
511
512 static void testGetInterfaceInfo(void)
513 {
514   if (gGetInterfaceInfo) {
515     DWORD apiReturn;
516     ULONG len = 0;
517
518     apiReturn = gGetInterfaceInfo(NULL, NULL);
519     if (apiReturn == ERROR_NOT_SUPPORTED) {
520       skip("GetInterfaceInfo is not supported\n");
521       return;
522     }
523     ok(apiReturn == ERROR_INVALID_PARAMETER,
524      "GetInterfaceInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
525      apiReturn);
526     apiReturn = gGetInterfaceInfo(NULL, &len);
527     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
528      "GetInterfaceInfo returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
529      apiReturn);
530     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
531       PIP_INTERFACE_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
532
533       apiReturn = gGetInterfaceInfo(buf, &len);
534       ok(apiReturn == NO_ERROR,
535        "GetInterfaceInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
536        apiReturn);
537       HeapFree(GetProcessHeap(), 0, buf);
538     }
539   }
540 }
541
542 static void testGetAdaptersInfo(void)
543 {
544   if (gGetAdaptersInfo) {
545     DWORD apiReturn;
546     ULONG len = 0;
547
548     apiReturn = gGetAdaptersInfo(NULL, NULL);
549     if (apiReturn == ERROR_NOT_SUPPORTED) {
550       skip("GetAdaptersInfo is not supported\n");
551       return;
552     }
553     ok(apiReturn == ERROR_INVALID_PARAMETER,
554      "GetAdaptersInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
555      apiReturn);
556     apiReturn = gGetAdaptersInfo(NULL, &len);
557     ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_BUFFER_OVERFLOW,
558      "GetAdaptersInfo returned %d, expected ERROR_NO_DATA or ERROR_BUFFER_OVERFLOW\n",
559      apiReturn);
560     if (apiReturn == ERROR_NO_DATA)
561       ; /* no adapter's, that's okay */
562     else if (apiReturn == ERROR_BUFFER_OVERFLOW) {
563       PIP_ADAPTER_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
564
565       apiReturn = gGetAdaptersInfo(buf, &len);
566       ok(apiReturn == NO_ERROR,
567        "GetAdaptersInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
568        apiReturn);
569       HeapFree(GetProcessHeap(), 0, buf);
570     }
571   }
572 }
573
574 static void testGetNetworkParams(void)
575 {
576   if (gGetNetworkParams) {
577     DWORD apiReturn;
578     ULONG len = 0;
579
580     apiReturn = gGetNetworkParams(NULL, NULL);
581     if (apiReturn == ERROR_NOT_SUPPORTED) {
582       skip("GetNetworkParams is not supported\n");
583       return;
584     }
585     ok(apiReturn == ERROR_INVALID_PARAMETER,
586      "GetNetworkParams returned %d, expected ERROR_INVALID_PARAMETER\n",
587      apiReturn);
588     apiReturn = gGetNetworkParams(NULL, &len);
589     ok(apiReturn == ERROR_BUFFER_OVERFLOW,
590      "GetNetworkParams returned %d, expected ERROR_BUFFER_OVERFLOW\n",
591      apiReturn);
592     if (apiReturn == ERROR_BUFFER_OVERFLOW) {
593       PFIXED_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
594
595       apiReturn = gGetNetworkParams(buf, &len);
596       ok(apiReturn == NO_ERROR,
597        "GetNetworkParams(buf, &dwSize) returned %d, expected NO_ERROR\n",
598        apiReturn);
599       HeapFree(GetProcessHeap(), 0, buf);
600     }
601   }
602 }
603
604 /*
605 still-to-be-tested 98-onward functions:
606 GetBestInterface
607 GetBestRoute
608 IpReleaseAddress
609 IpRenewAddress
610 */
611 static void testWin98Functions(void)
612 {
613   testGetInterfaceInfo();
614   testGetAdaptersInfo();
615   testGetNetworkParams();
616 }
617
618 static void testGetPerAdapterInfo(void)
619 {
620     DWORD ret, needed;
621     void *buffer;
622
623     if (!gGetPerAdapterInfo) return;
624     ret = gGetPerAdapterInfo(1, NULL, NULL);
625     if (ret == ERROR_NOT_SUPPORTED) {
626       skip("GetPerAdapterInfo is not supported\n");
627       return;
628     }
629     ok( ret == ERROR_INVALID_PARAMETER, "got %u instead of ERROR_INVALID_PARAMETER\n", ret );
630     needed = 0xdeadbeef;
631     ret = gGetPerAdapterInfo(1, NULL, &needed);
632     if (ret == ERROR_NO_DATA) return;  /* no such adapter */
633     ok( ret == ERROR_BUFFER_OVERFLOW, "got %u instead of ERROR_BUFFER_OVERFLOW\n", ret );
634     ok( needed != 0xdeadbeef, "needed not set\n" );
635     buffer = HeapAlloc( GetProcessHeap(), 0, needed );
636     ret = gGetPerAdapterInfo(1, buffer, &needed);
637     ok( ret == NO_ERROR, "got %u instead of NO_ERROR\n", ret );
638     HeapFree( GetProcessHeap(), 0, buffer );
639 }
640
641 /*
642 still-to-be-tested 2K-onward functions:
643 AddIPAddress
644 CreateProxyArpEntry
645 DeleteIPAddress
646 DeleteProxyArpEntry
647 EnableRouter
648 FlushIpNetTable
649 GetAdapterIndex
650 NotifyAddrChange
651 NotifyRouteChange
652 SendARP
653 UnenableRouter
654 */
655 static void testWin2KFunctions(void)
656 {
657     testGetPerAdapterInfo();
658 }
659
660 START_TEST(iphlpapi)
661 {
662
663   loadIPHlpApi();
664   if (hLibrary) {
665     testWin98OnlyFunctions();
666     testWinNT4Functions();
667     testWin98Functions();
668     testWin2KFunctions();
669     freeIPHlpApi();
670   }
671 }