xref: /reactos/modules/rostests/winetests/ntdll/rtl.c (revision 845faec4)
1 /* Unit test suite for Rtl* API functions
2  *
3  * Copyright 2003 Thomas Mertes
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
19  * NOTES
20  * We use function pointers here as there is no import library for NTDLL on
21  * windows.
22  */
23 
24 #include "ntdll_test.h"
25 
26 #include <inaddr.h>
27 #include <in6addr.h>
28 #include <objbase.h>
29 #include <initguid.h>
30 #define COBJMACROS
31 #include <shobjidl.h>
32 
33 #ifndef __WINE_WINTERNL_H
34 
35 typedef struct _RTL_HANDLE
36 {
37     struct _RTL_HANDLE * Next;
38 } RTL_HANDLE;
39 
40 typedef struct _RTL_HANDLE_TABLE
41 {
42     ULONG MaxHandleCount;
43     ULONG HandleSize;
44     ULONG Unused[2];
45     PVOID NextFree;
46     PVOID FirstHandle;
47     PVOID ReservedMemory;
48     PVOID MaxHandle;
49 } RTL_HANDLE_TABLE;
50 
51 #endif
52 
53 /* avoid #include <winsock2.h> */
54 #undef htons
55 #ifdef WORDS_BIGENDIAN
56 #define htons(s) ((USHORT)(s))
57 #else  /* WORDS_BIGENDIAN */
58 static inline USHORT __my_ushort_swap(USHORT s)
59 {
60     return (s >> 8) | (s << 8);
61 }
62 #define htons(s) __my_ushort_swap(s)
63 #endif  /* WORDS_BIGENDIAN */
64 
65 
66 
67 /* Function ptrs for ntdll calls */
68 static HMODULE hntdll = 0;
69 static SIZE_T    (WINAPI  *pRtlCompareMemory)(LPCVOID,LPCVOID,SIZE_T);
70 static SIZE_T    (WINAPI  *pRtlCompareMemoryUlong)(PULONG, SIZE_T, ULONG);
71 static NTSTATUS  (WINAPI  *pRtlDeleteTimer)(HANDLE, HANDLE, HANDLE);
72 static VOID      (WINAPI  *pRtlMoveMemory)(LPVOID,LPCVOID,SIZE_T);
73 static VOID      (WINAPI  *pRtlFillMemory)(LPVOID,SIZE_T,BYTE);
74 static VOID      (WINAPI  *pRtlFillMemoryUlong)(LPVOID,SIZE_T,ULONG);
75 static VOID      (WINAPI  *pRtlZeroMemory)(LPVOID,SIZE_T);
76 static ULONGLONG (WINAPIV *pRtlUlonglongByteSwap)(ULONGLONG source);
77 static ULONG     (WINAPI  *pRtlUniform)(PULONG);
78 static ULONG     (WINAPI  *pRtlRandom)(PULONG);
79 static BOOLEAN   (WINAPI  *pRtlAreAllAccessesGranted)(ACCESS_MASK, ACCESS_MASK);
80 static BOOLEAN   (WINAPI  *pRtlAreAnyAccessesGranted)(ACCESS_MASK, ACCESS_MASK);
81 static DWORD     (WINAPI  *pRtlComputeCrc32)(DWORD,const BYTE*,INT);
82 static void      (WINAPI * pRtlInitializeHandleTable)(ULONG, ULONG, RTL_HANDLE_TABLE *);
83 static BOOLEAN   (WINAPI * pRtlIsValidIndexHandle)(const RTL_HANDLE_TABLE *, ULONG, RTL_HANDLE **);
84 static NTSTATUS  (WINAPI * pRtlDestroyHandleTable)(RTL_HANDLE_TABLE *);
85 static RTL_HANDLE * (WINAPI * pRtlAllocateHandle)(RTL_HANDLE_TABLE *, ULONG *);
86 static BOOLEAN   (WINAPI * pRtlFreeHandle)(RTL_HANDLE_TABLE *, RTL_HANDLE *);
87 static NTSTATUS  (WINAPI *pRtlAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY,BYTE,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,PSID*);
88 static NTSTATUS  (WINAPI *pRtlFreeSid)(PSID);
89 static DWORD     (WINAPI *pRtlGetThreadErrorMode)(void);
90 static NTSTATUS  (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD);
91 static IMAGE_BASE_RELOCATION *(WINAPI *pLdrProcessRelocationBlock)(void*,UINT,USHORT*,INT_PTR);
92 static CHAR *    (WINAPI *pRtlIpv4AddressToStringA)(const IN_ADDR *, LPSTR);
93 static NTSTATUS  (WINAPI *pRtlIpv4AddressToStringExA)(const IN_ADDR *, USHORT, LPSTR, PULONG);
94 static NTSTATUS  (WINAPI *pRtlIpv4StringToAddressA)(PCSTR, BOOLEAN, PCSTR *, IN_ADDR *);
95 static NTSTATUS  (WINAPI *pRtlIpv4StringToAddressExA)(PCSTR, BOOLEAN, IN_ADDR *, PUSHORT);
96 static CHAR *    (WINAPI *pRtlIpv6AddressToStringA)(struct in6_addr *, PSTR);
97 static NTSTATUS  (WINAPI *pRtlIpv6AddressToStringExA)(struct in6_addr *, ULONG, USHORT, PCHAR, PULONG);
98 static NTSTATUS  (WINAPI *pRtlIpv6StringToAddressA)(PCSTR, PCSTR *, struct in6_addr *);
99 static NTSTATUS  (WINAPI *pRtlIpv6StringToAddressW)(PCWSTR, PCWSTR *, struct in6_addr *);
100 static NTSTATUS  (WINAPI *pRtlIpv6StringToAddressExA)(PCSTR, struct in6_addr *, PULONG, PUSHORT);
101 static NTSTATUS  (WINAPI *pRtlIpv6StringToAddressExW)(PCWSTR, struct in6_addr *, PULONG, PUSHORT);
102 static NTSTATUS  (WINAPI *pLdrAddRefDll)(ULONG, HMODULE);
103 static NTSTATUS  (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG*, ULONG_PTR*);
104 static NTSTATUS  (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
105 static NTSTATUS  (WINAPI *pRtlMultiByteToUnicodeN)(LPWSTR, DWORD, LPDWORD, LPCSTR, DWORD);
106 static NTSTATUS  (WINAPI *pRtlGetCompressionWorkSpaceSize)(USHORT, PULONG, PULONG);
107 static NTSTATUS  (WINAPI *pRtlDecompressBuffer)(USHORT, PUCHAR, ULONG, const UCHAR*, ULONG, PULONG);
108 static NTSTATUS  (WINAPI *pRtlDecompressFragment)(USHORT, PUCHAR, ULONG, const UCHAR*, ULONG, ULONG, PULONG, PVOID);
109 static NTSTATUS  (WINAPI *pRtlCompressBuffer)(USHORT, const UCHAR*, ULONG, PUCHAR, ULONG, ULONG, PULONG, PVOID);
110 static BOOL      (WINAPI *pRtlIsCriticalSectionLocked)(CRITICAL_SECTION *);
111 static BOOL      (WINAPI *pRtlIsCriticalSectionLockedByThread)(CRITICAL_SECTION *);
112 static NTSTATUS  (WINAPI *pRtlInitializeCriticalSectionEx)(CRITICAL_SECTION *, ULONG, ULONG);
113 static NTSTATUS  (WINAPI *pLdrEnumerateLoadedModules)(void *, void *, void *);
114 static NTSTATUS  (WINAPI *pRtlQueryPackageIdentity)(HANDLE, WCHAR*, SIZE_T*, WCHAR*, SIZE_T*, BOOLEAN*);
115 static NTSTATUS  (WINAPI *pLdrRegisterDllNotification)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, void *, void **);
116 static NTSTATUS  (WINAPI *pLdrUnregisterDllNotification)(void *);
117 
118 static HMODULE hkernel32 = 0;
119 static BOOL      (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
120 
121 
122 #define LEN 16
123 static const char* src_src = "This is a test!"; /* 16 bytes long, incl NUL */
124 static WCHAR ws2_32dllW[] = {'w','s','2','_','3','2','.','d','l','l',0};
125 static WCHAR wintrustdllW[] = {'w','i','n','t','r','u','s','t','.','d','l','l',0};
126 static WCHAR crypt32dllW[] = {'c','r','y','p','t','3','2','.','d','l','l',0};
127 static ULONG src_aligned_block[4];
128 static ULONG dest_aligned_block[32];
129 static const char *src = (const char*)src_aligned_block;
130 static char* dest = (char*)dest_aligned_block;
131 
132 static void InitFunctionPtrs(void)
133 {
134     hntdll = LoadLibraryA("ntdll.dll");
135     ok(hntdll != 0, "LoadLibrary failed\n");
136     if (hntdll) {
137 	pRtlCompareMemory = (void *)GetProcAddress(hntdll, "RtlCompareMemory");
138 	pRtlCompareMemoryUlong = (void *)GetProcAddress(hntdll, "RtlCompareMemoryUlong");
139         pRtlDeleteTimer = (void *)GetProcAddress(hntdll, "RtlDeleteTimer");
140 	pRtlMoveMemory = (void *)GetProcAddress(hntdll, "RtlMoveMemory");
141 	pRtlFillMemory = (void *)GetProcAddress(hntdll, "RtlFillMemory");
142 	pRtlFillMemoryUlong = (void *)GetProcAddress(hntdll, "RtlFillMemoryUlong");
143 	pRtlZeroMemory = (void *)GetProcAddress(hntdll, "RtlZeroMemory");
144 	pRtlUlonglongByteSwap = (void *)GetProcAddress(hntdll, "RtlUlonglongByteSwap");
145 	pRtlUniform = (void *)GetProcAddress(hntdll, "RtlUniform");
146 	pRtlRandom = (void *)GetProcAddress(hntdll, "RtlRandom");
147 	pRtlAreAllAccessesGranted = (void *)GetProcAddress(hntdll, "RtlAreAllAccessesGranted");
148 	pRtlAreAnyAccessesGranted = (void *)GetProcAddress(hntdll, "RtlAreAnyAccessesGranted");
149 	pRtlComputeCrc32 = (void *)GetProcAddress(hntdll, "RtlComputeCrc32");
150 	pRtlInitializeHandleTable = (void *)GetProcAddress(hntdll, "RtlInitializeHandleTable");
151 	pRtlIsValidIndexHandle = (void *)GetProcAddress(hntdll, "RtlIsValidIndexHandle");
152 	pRtlDestroyHandleTable = (void *)GetProcAddress(hntdll, "RtlDestroyHandleTable");
153 	pRtlAllocateHandle = (void *)GetProcAddress(hntdll, "RtlAllocateHandle");
154 	pRtlFreeHandle = (void *)GetProcAddress(hntdll, "RtlFreeHandle");
155         pRtlAllocateAndInitializeSid = (void *)GetProcAddress(hntdll, "RtlAllocateAndInitializeSid");
156         pRtlFreeSid = (void *)GetProcAddress(hntdll, "RtlFreeSid");
157         pRtlGetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlGetThreadErrorMode");
158         pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode");
159         pLdrProcessRelocationBlock  = (void *)GetProcAddress(hntdll, "LdrProcessRelocationBlock");
160         pRtlIpv4AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringA");
161         pRtlIpv4AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv4AddressToStringExA");
162         pRtlIpv4StringToAddressA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressA");
163         pRtlIpv4StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv4StringToAddressExA");
164         pRtlIpv6AddressToStringA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringA");
165         pRtlIpv6AddressToStringExA = (void *)GetProcAddress(hntdll, "RtlIpv6AddressToStringExA");
166         pRtlIpv6StringToAddressA = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressA");
167         pRtlIpv6StringToAddressW = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressW");
168         pRtlIpv6StringToAddressExA = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExA");
169         pRtlIpv6StringToAddressExW = (void *)GetProcAddress(hntdll, "RtlIpv6StringToAddressExW");
170         pLdrAddRefDll = (void *)GetProcAddress(hntdll, "LdrAddRefDll");
171         pLdrLockLoaderLock = (void *)GetProcAddress(hntdll, "LdrLockLoaderLock");
172         pLdrUnlockLoaderLock = (void *)GetProcAddress(hntdll, "LdrUnlockLoaderLock");
173         pRtlMultiByteToUnicodeN = (void *)GetProcAddress(hntdll, "RtlMultiByteToUnicodeN");
174         pRtlGetCompressionWorkSpaceSize = (void *)GetProcAddress(hntdll, "RtlGetCompressionWorkSpaceSize");
175         pRtlDecompressBuffer = (void *)GetProcAddress(hntdll, "RtlDecompressBuffer");
176         pRtlDecompressFragment = (void *)GetProcAddress(hntdll, "RtlDecompressFragment");
177         pRtlCompressBuffer = (void *)GetProcAddress(hntdll, "RtlCompressBuffer");
178         pRtlIsCriticalSectionLocked = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLocked");
179         pRtlIsCriticalSectionLockedByThread = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLockedByThread");
180         pRtlInitializeCriticalSectionEx = (void *)GetProcAddress(hntdll, "RtlInitializeCriticalSectionEx");
181         pLdrEnumerateLoadedModules = (void *)GetProcAddress(hntdll, "LdrEnumerateLoadedModules");
182         pRtlQueryPackageIdentity = (void *)GetProcAddress(hntdll, "RtlQueryPackageIdentity");
183         pLdrRegisterDllNotification = (void *)GetProcAddress(hntdll, "LdrRegisterDllNotification");
184         pLdrUnregisterDllNotification = (void *)GetProcAddress(hntdll, "LdrUnregisterDllNotification");
185     }
186     hkernel32 = LoadLibraryA("kernel32.dll");
187     ok(hkernel32 != 0, "LoadLibrary failed\n");
188     if (hkernel32) {
189         pIsWow64Process = (void *)GetProcAddress(hkernel32, "IsWow64Process");
190     }
191     strcpy((char*)src_aligned_block, src_src);
192     ok(strlen(src) == 15, "Source must be 16 bytes long!\n");
193 }
194 
195 #define COMP(str1,str2,cmplen,len) size = pRtlCompareMemory(str1, str2, cmplen); \
196   ok(size == len, "Expected %ld, got %ld\n", size, (SIZE_T)len)
197 
198 static void test_RtlCompareMemory(void)
199 {
200   SIZE_T size;
201 
202   if (!pRtlCompareMemory)
203   {
204     win_skip("RtlCompareMemory is not available\n");
205     return;
206   }
207 
208   strcpy(dest, src);
209 
210   COMP(src,src,0,0);
211   COMP(src,src,LEN,LEN);
212   dest[0] = 'x';
213   COMP(src,dest,LEN,0);
214 }
215 
216 static void test_RtlCompareMemoryUlong(void)
217 {
218     ULONG a[10];
219     ULONG result;
220 
221     if (!pRtlCompareMemoryUlong)
222     {
223         win_skip("RtlCompareMemoryUlong is not available\n");
224         return;
225     }
226 
227     a[0]= 0x0123;
228     a[1]= 0x4567;
229     a[2]= 0x89ab;
230     a[3]= 0xcdef;
231     result = pRtlCompareMemoryUlong(a, 0, 0x0123);
232     ok(result == 0, "RtlCompareMemoryUlong(%p, 0, 0x0123) returns %u, expected 0\n", a, result);
233     result = pRtlCompareMemoryUlong(a, 3, 0x0123);
234     ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %u, expected 0\n", a, result);
235     result = pRtlCompareMemoryUlong(a, 4, 0x0123);
236     ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %u, expected 4\n", a, result);
237     result = pRtlCompareMemoryUlong(a, 5, 0x0123);
238     ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %u, expected 4\n", a, result);
239     result = pRtlCompareMemoryUlong(a, 7, 0x0123);
240     ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %u, expected 4\n", a, result);
241     result = pRtlCompareMemoryUlong(a, 8, 0x0123);
242     ok(result == 4, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %u, expected 4\n", a, result);
243     result = pRtlCompareMemoryUlong(a, 9, 0x0123);
244     ok(result == 4, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %u, expected 4\n", a, result);
245     result = pRtlCompareMemoryUlong(a, 4, 0x0127);
246     ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x0127) returns %u, expected 0\n", a, result);
247     result = pRtlCompareMemoryUlong(a, 4, 0x7123);
248     ok(result == 0, "RtlCompareMemoryUlong(%p, 4, 0x7123) returns %u, expected 0\n", a, result);
249     result = pRtlCompareMemoryUlong(a, 16, 0x4567);
250     ok(result == 0, "RtlCompareMemoryUlong(%p, 16, 0x4567) returns %u, expected 0\n", a, result);
251 
252     a[1]= 0x0123;
253     result = pRtlCompareMemoryUlong(a, 3, 0x0123);
254     ok(result == 0, "RtlCompareMemoryUlong(%p, 3, 0x0123) returns %u, expected 0\n", a, result);
255     result = pRtlCompareMemoryUlong(a, 4, 0x0123);
256     ok(result == 4, "RtlCompareMemoryUlong(%p, 4, 0x0123) returns %u, expected 4\n", a, result);
257     result = pRtlCompareMemoryUlong(a, 5, 0x0123);
258     ok(result == 4, "RtlCompareMemoryUlong(%p, 5, 0x0123) returns %u, expected 4\n", a, result);
259     result = pRtlCompareMemoryUlong(a, 7, 0x0123);
260     ok(result == 4, "RtlCompareMemoryUlong(%p, 7, 0x0123) returns %u, expected 4\n", a, result);
261     result = pRtlCompareMemoryUlong(a, 8, 0x0123);
262     ok(result == 8, "RtlCompareMemoryUlong(%p, 8, 0x0123) returns %u, expected 8\n", a, result);
263     result = pRtlCompareMemoryUlong(a, 9, 0x0123);
264     ok(result == 8, "RtlCompareMemoryUlong(%p, 9, 0x0123) returns %u, expected 8\n", a, result);
265 }
266 
267 #define COPY(len) memset(dest,0,sizeof(dest_aligned_block)); pRtlMoveMemory(dest, src, len)
268 #define CMP(str) ok(strcmp(dest,str) == 0, "Expected '%s', got '%s'\n", str, dest)
269 
270 static void test_RtlMoveMemory(void)
271 {
272   if (!pRtlMoveMemory)
273   {
274     win_skip("RtlMoveMemory is not available\n");
275     return;
276   }
277 
278   /* Length should be in bytes and not rounded. Use strcmp to ensure we
279    * didn't write past the end (it checks for the final NUL left by memset)
280    */
281   COPY(0); CMP("");
282   COPY(1); CMP("T");
283   COPY(2); CMP("Th");
284   COPY(3); CMP("Thi");
285   COPY(4); CMP("This");
286   COPY(5); CMP("This ");
287   COPY(6); CMP("This i");
288   COPY(7); CMP("This is");
289   COPY(8); CMP("This is ");
290   COPY(9); CMP("This is a");
291 
292   /* Overlapping */
293   strcpy(dest, src); pRtlMoveMemory(dest, dest + 1, strlen(src) - 1);
294   CMP("his is a test!!");
295   strcpy(dest, src); pRtlMoveMemory(dest + 1, dest, strlen(src));
296   CMP("TThis is a test!");
297 }
298 
299 #define FILL(len) memset(dest,0,sizeof(dest_aligned_block)); strcpy(dest, src); pRtlFillMemory(dest,len,'x')
300 
301 static void test_RtlFillMemory(void)
302 {
303   if (!pRtlFillMemory)
304   {
305     win_skip("RtlFillMemory is not available\n");
306     return;
307   }
308 
309   /* Length should be in bytes and not rounded. Use strcmp to ensure we
310    * didn't write past the end (the remainder of the string should match)
311    */
312   FILL(0); CMP("This is a test!");
313   FILL(1); CMP("xhis is a test!");
314   FILL(2); CMP("xxis is a test!");
315   FILL(3); CMP("xxxs is a test!");
316   FILL(4); CMP("xxxx is a test!");
317   FILL(5); CMP("xxxxxis a test!");
318   FILL(6); CMP("xxxxxxs a test!");
319   FILL(7); CMP("xxxxxxx a test!");
320   FILL(8); CMP("xxxxxxxxa test!");
321   FILL(9); CMP("xxxxxxxxx test!");
322 }
323 
324 #define LFILL(len) memset(dest,0,sizeof(dest_aligned_block)); strcpy(dest, src); pRtlFillMemoryUlong(dest,len,val)
325 
326 static void test_RtlFillMemoryUlong(void)
327 {
328   ULONG val = ('x' << 24) | ('x' << 16) | ('x' << 8) | 'x';
329   if (!pRtlFillMemoryUlong)
330   {
331     win_skip("RtlFillMemoryUlong is not available\n");
332     return;
333   }
334 
335   /* Length should be in bytes and not rounded. Use strcmp to ensure we
336    * didn't write past the end (the remainder of the string should match)
337    */
338   LFILL(0); CMP("This is a test!");
339   LFILL(1); CMP("This is a test!");
340   LFILL(2); CMP("This is a test!");
341   LFILL(3); CMP("This is a test!");
342   LFILL(4); CMP("xxxx is a test!");
343   LFILL(5); CMP("xxxx is a test!");
344   LFILL(6); CMP("xxxx is a test!");
345   LFILL(7); CMP("xxxx is a test!");
346   LFILL(8); CMP("xxxxxxxxa test!");
347   LFILL(9); CMP("xxxxxxxxa test!");
348 }
349 
350 #define ZERO(len) memset(dest,0,sizeof(dest_aligned_block)); strcpy(dest, src); pRtlZeroMemory(dest,len)
351 #define MCMP(str) ok(memcmp(dest,str,LEN) == 0, "Memcmp failed\n")
352 
353 static void test_RtlZeroMemory(void)
354 {
355   if (!pRtlZeroMemory)
356   {
357     win_skip("RtlZeroMemory is not available\n");
358     return;
359   }
360 
361   /* Length should be in bytes and not rounded. */
362   ZERO(0); MCMP("This is a test!");
363   ZERO(1); MCMP("\0his is a test!");
364   ZERO(2); MCMP("\0\0is is a test!");
365   ZERO(3); MCMP("\0\0\0s is a test!");
366   ZERO(4); MCMP("\0\0\0\0 is a test!");
367   ZERO(5); MCMP("\0\0\0\0\0is a test!");
368   ZERO(6); MCMP("\0\0\0\0\0\0s a test!");
369   ZERO(7); MCMP("\0\0\0\0\0\0\0 a test!");
370   ZERO(8); MCMP("\0\0\0\0\0\0\0\0a test!");
371   ZERO(9); MCMP("\0\0\0\0\0\0\0\0\0 test!");
372 }
373 
374 static void test_RtlUlonglongByteSwap(void)
375 {
376     ULONGLONG result;
377 
378     if ( !pRtlUlonglongByteSwap )
379     {
380         win_skip("RtlUlonglongByteSwap is not available\n");
381         return;
382     }
383 
384     if ( pRtlUlonglongByteSwap( 0 ) != 0 )
385     {
386         win_skip("Broken RtlUlonglongByteSwap in win2k\n");
387         return;
388     }
389 
390     result = pRtlUlonglongByteSwap( ((ULONGLONG)0x76543210 << 32) | 0x87654321 );
391     ok( (((ULONGLONG)0x21436587 << 32) | 0x10325476) == result,
392        "RtlUlonglongByteSwap(0x7654321087654321) returns 0x%s, expected 0x2143658710325476\n",
393        wine_dbgstr_longlong(result));
394 }
395 
396 
397 static void test_RtlUniform(void)
398 {
399     ULONGLONG num;
400     ULONG seed;
401     ULONG seed_bak;
402     ULONG expected;
403     ULONG result;
404 
405     if (!pRtlUniform)
406     {
407         win_skip("RtlUniform is not available\n");
408         return;
409     }
410 
411 /*
412  * According to the documentation RtlUniform is using D.H. Lehmer's 1948
413  * algorithm. This algorithm is:
414  *
415  * seed = (seed * const_1 + const_2) % const_3;
416  *
417  * According to the documentation the random number is distributed over
418  * [0..MAXLONG]. Therefore const_3 is MAXLONG + 1:
419  *
420  * seed = (seed * const_1 + const_2) % (MAXLONG + 1);
421  *
422  * Because MAXLONG is 0x7fffffff (and MAXLONG + 1 is 0x80000000) the
423  * algorithm can be expressed without division as:
424  *
425  * seed = (seed * const_1 + const_2) & MAXLONG;
426  *
427  * To find out const_2 we just call RtlUniform with seed set to 0:
428  */
429     seed = 0;
430     expected = 0x7fffffc3;
431     result = pRtlUniform(&seed);
432     ok(result == expected,
433         "RtlUniform(&seed (seed == 0)) returns %x, expected %x\n",
434         result, expected);
435 /*
436  * The algorithm is now:
437  *
438  * seed = (seed * const_1 + 0x7fffffc3) & MAXLONG;
439  *
440  * To find out const_1 we can use:
441  *
442  * const_1 = RtlUniform(1) - 0x7fffffc3;
443  *
444  * If that does not work a search loop can try all possible values of
445  * const_1 and compare to the result to RtlUniform(1).
446  * This way we find out that const_1 is 0xffffffed.
447  *
448  * For seed = 1 the const_2 is 0x7fffffc4:
449  */
450     seed = 1;
451     expected = seed * 0xffffffed + 0x7fffffc3 + 1;
452     result = pRtlUniform(&seed);
453     ok(result == expected,
454         "RtlUniform(&seed (seed == 1)) returns %x, expected %x\n",
455         result, expected);
456 /*
457  * For seed = 2 the const_2 is 0x7fffffc3:
458  */
459     seed = 2;
460     expected = seed * 0xffffffed + 0x7fffffc3;
461     result = pRtlUniform(&seed);
462 
463 /*
464  * Windows Vista uses different algorithms, so skip the rest of the tests
465  * until that is figured out. Trace output for the failures is about 10.5 MB!
466  */
467 
468     if (result == 0x7fffff9f) {
469         skip("Most likely running on Windows Vista which uses a different algorithm\n");
470         return;
471     }
472 
473     ok(result == expected,
474         "RtlUniform(&seed (seed == 2)) returns %x, expected %x\n",
475         result, expected);
476 
477 /*
478  * More tests show that if seed is odd the result must be incremented by 1:
479  */
480     seed = 3;
481     expected = seed * 0xffffffed + 0x7fffffc3 + (seed & 1);
482     result = pRtlUniform(&seed);
483     ok(result == expected,
484         "RtlUniform(&seed (seed == 3)) returns %x, expected %x\n",
485         result, expected);
486 
487     seed = 0x6bca1aa;
488     expected = seed * 0xffffffed + 0x7fffffc3;
489     result = pRtlUniform(&seed);
490     ok(result == expected,
491         "RtlUniform(&seed (seed == 0x6bca1aa)) returns %x, expected %x\n",
492         result, expected);
493 
494     seed = 0x6bca1ab;
495     expected = seed * 0xffffffed + 0x7fffffc3 + 1;
496     result = pRtlUniform(&seed);
497     ok(result == expected,
498         "RtlUniform(&seed (seed == 0x6bca1ab)) returns %x, expected %x\n",
499         result, expected);
500 /*
501  * When seed is 0x6bca1ac there is an exception:
502  */
503     seed = 0x6bca1ac;
504     expected = seed * 0xffffffed + 0x7fffffc3 + 2;
505     result = pRtlUniform(&seed);
506     ok(result == expected,
507         "RtlUniform(&seed (seed == 0x6bca1ac)) returns %x, expected %x\n",
508         result, expected);
509 /*
510  * Note that up to here const_3 is not used
511  * (the highest bit of the result is not set).
512  *
513  * Starting with 0x6bca1ad: If seed is even the result must be incremented by 1:
514  */
515     seed = 0x6bca1ad;
516     expected = (seed * 0xffffffed + 0x7fffffc3) & MAXLONG;
517     result = pRtlUniform(&seed);
518     ok(result == expected,
519         "RtlUniform(&seed (seed == 0x6bca1ad)) returns %x, expected %x\n",
520         result, expected);
521 
522     seed = 0x6bca1ae;
523     expected = (seed * 0xffffffed + 0x7fffffc3 + 1) & MAXLONG;
524     result = pRtlUniform(&seed);
525     ok(result == expected,
526         "RtlUniform(&seed (seed == 0x6bca1ae)) returns %x, expected %x\n",
527         result, expected);
528 /*
529  * There are several ranges where for odd or even seed the result must be
530  * incremented by 1. You can see this ranges in the following test.
531  *
532  * For a full test use one of the following loop heads:
533  *
534  *  for (num = 0; num <= 0xffffffff; num++) {
535  *      seed = num;
536  *      ...
537  *
538  *  seed = 0;
539  *  for (num = 0; num <= 0xffffffff; num++) {
540  *      ...
541  */
542     seed = 0;
543     for (num = 0; num <= 100000; num++) {
544 
545 	expected = seed * 0xffffffed + 0x7fffffc3;
546 	if (seed < 0x6bca1ac) {
547 	    expected = expected + (seed & 1);
548 	} else if (seed == 0x6bca1ac) {
549 	    expected = (expected + 2) & MAXLONG;
550 	} else if (seed < 0xd79435c) {
551 	    expected = (expected + (~seed & 1)) & MAXLONG;
552 	} else if (seed < 0x1435e50b) {
553 	    expected = expected + (seed & 1);
554 	} else if (seed < 0x1af286ba) {
555 	    expected = (expected + (~seed & 1)) & MAXLONG;
556 	} else if (seed < 0x21af2869) {
557 	    expected = expected + (seed & 1);
558 	} else if (seed < 0x286bca18) {
559 	    expected = (expected + (~seed & 1)) & MAXLONG;
560 	} else if (seed < 0x2f286bc7) {
561 	    expected = expected + (seed & 1);
562 	} else if (seed < 0x35e50d77) {
563 	    expected = (expected + (~seed & 1)) & MAXLONG;
564 	} else if (seed < 0x3ca1af26) {
565 	    expected = expected + (seed & 1);
566 	} else if (seed < 0x435e50d5) {
567 	    expected = (expected + (~seed & 1)) & MAXLONG;
568 	} else if (seed < 0x4a1af284) {
569 	    expected = expected + (seed & 1);
570 	} else if (seed < 0x50d79433) {
571 	    expected = (expected + (~seed & 1)) & MAXLONG;
572 	} else if (seed < 0x579435e2) {
573 	    expected = expected + (seed & 1);
574 	} else if (seed < 0x5e50d792) {
575 	    expected = (expected + (~seed & 1)) & MAXLONG;
576 	} else if (seed < 0x650d7941) {
577 	    expected = expected + (seed & 1);
578 	} else if (seed < 0x6bca1af0) {
579 	    expected = (expected + (~seed & 1)) & MAXLONG;
580 	} else if (seed < 0x7286bc9f) {
581 	    expected = expected + (seed & 1);
582 	} else if (seed < 0x79435e4e) {
583 	    expected = (expected + (~seed & 1)) & MAXLONG;
584 	} else if (seed < 0x7ffffffd) {
585 	    expected = expected + (seed & 1);
586 	} else if (seed < 0x86bca1ac) {
587 	    expected = (expected + (~seed & 1)) & MAXLONG;
588 	} else if (seed == 0x86bca1ac) {
589 	    expected = (expected + 1) & MAXLONG;
590 	} else if (seed < 0x8d79435c) {
591 	    expected = expected + (seed & 1);
592 	} else if (seed < 0x9435e50b) {
593 	    expected = (expected + (~seed & 1)) & MAXLONG;
594 	} else if (seed < 0x9af286ba) {
595 	    expected = expected + (seed & 1);
596 	} else if (seed < 0xa1af2869) {
597 	    expected = (expected + (~seed & 1)) & MAXLONG;
598 	} else if (seed < 0xa86bca18) {
599 	    expected = expected + (seed & 1);
600 	} else if (seed < 0xaf286bc7) {
601 	    expected = (expected + (~seed & 1)) & MAXLONG;
602 	} else if (seed == 0xaf286bc7) {
603 	    expected = (expected + 2) & MAXLONG;
604 	} else if (seed < 0xb5e50d77) {
605 	    expected = expected + (seed & 1);
606 	} else if (seed < 0xbca1af26) {
607 	    expected = (expected + (~seed & 1)) & MAXLONG;
608 	} else if (seed < 0xc35e50d5) {
609 	    expected = expected + (seed & 1);
610 	} else if (seed < 0xca1af284) {
611 	    expected = (expected + (~seed & 1)) & MAXLONG;
612 	} else if (seed < 0xd0d79433) {
613 	    expected = expected + (seed & 1);
614 	} else if (seed < 0xd79435e2) {
615 	    expected = (expected + (~seed & 1)) & MAXLONG;
616 	} else if (seed < 0xde50d792) {
617 	    expected = expected + (seed & 1);
618 	} else if (seed < 0xe50d7941) {
619 	    expected = (expected + (~seed & 1)) & MAXLONG;
620 	} else if (seed < 0xebca1af0) {
621 	    expected = expected + (seed & 1);
622 	} else if (seed < 0xf286bc9f) {
623 	    expected = (expected + (~seed & 1)) & MAXLONG;
624 	} else if (seed < 0xf9435e4e) {
625 	    expected = expected + (seed & 1);
626 	} else if (seed < 0xfffffffd) {
627 	    expected = (expected + (~seed & 1)) & MAXLONG;
628 	} else {
629 	    expected = expected + (seed & 1);
630 	} /* if */
631         seed_bak = seed;
632         result = pRtlUniform(&seed);
633         ok(result == expected,
634                 "test: 0x%s RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
635                 wine_dbgstr_longlong(num), seed_bak, result, expected);
636         ok(seed == expected,
637                 "test: 0x%s RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
638                 wine_dbgstr_longlong(num), seed_bak, result, expected);
639     } /* for */
640 /*
641  * Further investigation shows: In the different regions the highest bit
642  * is set or cleared when even or odd seeds need an increment by 1.
643  * This leads to a simplified algorithm:
644  *
645  * seed = seed * 0xffffffed + 0x7fffffc3;
646  * if (seed == 0xffffffff || seed == 0x7ffffffe) {
647  *     seed = (seed + 2) & MAXLONG;
648  * } else if (seed == 0x7fffffff) {
649  *     seed = 0;
650  * } else if ((seed & 0x80000000) == 0) {
651  *     seed = seed + (~seed & 1);
652  * } else {
653  *     seed = (seed + (seed & 1)) & MAXLONG;
654  * }
655  *
656  * This is also the algorithm used for RtlUniform of wine (see dlls/ntdll/rtl.c).
657  *
658  * Now comes the funny part:
659  * It took me one weekend, to find the complicated algorithm and one day more,
660  * to find the simplified algorithm. Several weeks later I found out: The value
661  * MAXLONG (=0x7fffffff) is never returned, neither with the native function
662  * nor with the simplified algorithm. In reality the native function and our
663  * function return a random number distributed over [0..MAXLONG-1]. Note
664  * that this is different from what native documentation states [0..MAXLONG].
665  * Expressed with D.H. Lehmer's 1948 algorithm it looks like:
666  *
667  * seed = (seed * const_1 + const_2) % MAXLONG;
668  *
669  * Further investigations show that the real algorithm is:
670  *
671  * seed = (seed * 0x7fffffed + 0x7fffffc3) % MAXLONG;
672  *
673  * This is checked with the test below:
674  */
675     seed = 0;
676     for (num = 0; num <= 100000; num++) {
677 	expected = (seed * 0x7fffffed + 0x7fffffc3) % 0x7fffffff;
678         seed_bak = seed;
679         result = pRtlUniform(&seed);
680         ok(result == expected,
681                 "test: 0x%s RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
682                 wine_dbgstr_longlong(num), seed_bak, result, expected);
683         ok(seed == expected,
684                 "test: 0x%s RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
685                 wine_dbgstr_longlong(num), seed_bak, result, expected);
686     } /* for */
687 /*
688  * More tests show that RtlUniform does not return 0x7ffffffd for seed values
689  * in the range [0..MAXLONG-1]. Additionally 2 is returned twice. This shows
690  * that there is more than one cycle of generated randon numbers ...
691  */
692 }
693 
694 
695 static void test_RtlRandom(void)
696 {
697     int i, j;
698     ULONG seed;
699     ULONG res[512];
700 
701     if (!pRtlRandom)
702     {
703         win_skip("RtlRandom is not available\n");
704         return;
705     }
706 
707     seed = 0;
708     for (i = 0; i < sizeof(res) / sizeof(res[0]); i++)
709     {
710         res[i] = pRtlRandom(&seed);
711         ok(seed != res[i], "%i: seed is same as res %x\n", i, seed);
712         for (j = 0; j < i; j++)
713             ok(res[i] != res[j], "res[%i] (%x) is same as res[%i] (%x)\n", j, res[j], i, res[i]);
714     }
715 }
716 
717 
718 typedef struct {
719     ACCESS_MASK GrantedAccess;
720     ACCESS_MASK DesiredAccess;
721     BOOLEAN result;
722 } all_accesses_t;
723 
724 static const all_accesses_t all_accesses[] = {
725     {0xFEDCBA76, 0xFEDCBA76, 1},
726     {0x00000000, 0xFEDCBA76, 0},
727     {0xFEDCBA76, 0x00000000, 1},
728     {0x00000000, 0x00000000, 1},
729     {0xFEDCBA76, 0xFEDCBA70, 1},
730     {0xFEDCBA70, 0xFEDCBA76, 0},
731     {0xFEDCBA76, 0xFEDC8A76, 1},
732     {0xFEDC8A76, 0xFEDCBA76, 0},
733     {0xFEDCBA76, 0xC8C4B242, 1},
734     {0xC8C4B242, 0xFEDCBA76, 0},
735 };
736 #define NB_ALL_ACCESSES (sizeof(all_accesses)/sizeof(*all_accesses))
737 
738 
739 static void test_RtlAreAllAccessesGranted(void)
740 {
741     unsigned int test_num;
742     BOOLEAN result;
743 
744     if (!pRtlAreAllAccessesGranted)
745     {
746         win_skip("RtlAreAllAccessesGranted is not available\n");
747         return;
748     }
749 
750     for (test_num = 0; test_num < NB_ALL_ACCESSES; test_num++) {
751 	result = pRtlAreAllAccessesGranted(all_accesses[test_num].GrantedAccess,
752 					   all_accesses[test_num].DesiredAccess);
753 	ok(all_accesses[test_num].result == result,
754            "(test %d): RtlAreAllAccessesGranted(%08x, %08x) returns %d, expected %d\n",
755 	   test_num, all_accesses[test_num].GrantedAccess,
756 	   all_accesses[test_num].DesiredAccess,
757 	   result, all_accesses[test_num].result);
758     } /* for */
759 }
760 
761 
762 typedef struct {
763     ACCESS_MASK GrantedAccess;
764     ACCESS_MASK DesiredAccess;
765     BOOLEAN result;
766 } any_accesses_t;
767 
768 static const any_accesses_t any_accesses[] = {
769     {0xFEDCBA76, 0xFEDCBA76, 1},
770     {0x00000000, 0xFEDCBA76, 0},
771     {0xFEDCBA76, 0x00000000, 0},
772     {0x00000000, 0x00000000, 0},
773     {0xFEDCBA76, 0x01234589, 0},
774     {0x00040000, 0xFEDCBA76, 1},
775     {0x00040000, 0xFED8BA76, 0},
776     {0xFEDCBA76, 0x00040000, 1},
777     {0xFED8BA76, 0x00040000, 0},
778 };
779 #define NB_ANY_ACCESSES (sizeof(any_accesses)/sizeof(*any_accesses))
780 
781 
782 static void test_RtlAreAnyAccessesGranted(void)
783 {
784     unsigned int test_num;
785     BOOLEAN result;
786 
787     if (!pRtlAreAnyAccessesGranted)
788     {
789         win_skip("RtlAreAnyAccessesGranted is not available\n");
790         return;
791     }
792 
793     for (test_num = 0; test_num < NB_ANY_ACCESSES; test_num++) {
794 	result = pRtlAreAnyAccessesGranted(any_accesses[test_num].GrantedAccess,
795 					   any_accesses[test_num].DesiredAccess);
796 	ok(any_accesses[test_num].result == result,
797            "(test %d): RtlAreAnyAccessesGranted(%08x, %08x) returns %d, expected %d\n",
798 	   test_num, any_accesses[test_num].GrantedAccess,
799 	   any_accesses[test_num].DesiredAccess,
800 	   result, any_accesses[test_num].result);
801     } /* for */
802 }
803 
804 static void test_RtlComputeCrc32(void)
805 {
806   DWORD crc = 0;
807 
808   if (!pRtlComputeCrc32)
809   {
810     win_skip("RtlComputeCrc32 is not available\n");
811     return;
812   }
813 
814   crc = pRtlComputeCrc32(crc, (const BYTE *)src, LEN);
815   ok(crc == 0x40861dc2,"Expected 0x40861dc2, got %8x\n", crc);
816 }
817 
818 
819 typedef struct MY_HANDLE
820 {
821     RTL_HANDLE RtlHandle;
822     void * MyValue;
823 } MY_HANDLE;
824 
825 static inline void RtlpMakeHandleAllocated(RTL_HANDLE * Handle)
826 {
827     ULONG_PTR *AllocatedBit = (ULONG_PTR *)(&Handle->Next);
828     *AllocatedBit = *AllocatedBit | 1;
829 }
830 
831 static void test_HandleTables(void)
832 {
833     BOOLEAN result;
834     NTSTATUS status;
835     ULONG Index;
836     MY_HANDLE * MyHandle;
837     RTL_HANDLE_TABLE HandleTable;
838 
839     if (!pRtlInitializeHandleTable)
840     {
841         win_skip("RtlInitializeHandleTable is not available\n");
842         return;
843     }
844 
845     pRtlInitializeHandleTable(0x3FFF, sizeof(MY_HANDLE), &HandleTable);
846     MyHandle = (MY_HANDLE *)pRtlAllocateHandle(&HandleTable, &Index);
847     ok(MyHandle != NULL, "RtlAllocateHandle failed\n");
848     RtlpMakeHandleAllocated(&MyHandle->RtlHandle);
849     MyHandle = NULL;
850     result = pRtlIsValidIndexHandle(&HandleTable, Index, (RTL_HANDLE **)&MyHandle);
851     ok(result, "Handle %p wasn't valid\n", MyHandle);
852     result = pRtlFreeHandle(&HandleTable, &MyHandle->RtlHandle);
853     ok(result, "Couldn't free handle %p\n", MyHandle);
854     status = pRtlDestroyHandleTable(&HandleTable);
855     ok(status == STATUS_SUCCESS, "RtlDestroyHandleTable failed with error 0x%08x\n", status);
856 }
857 
858 static void test_RtlAllocateAndInitializeSid(void)
859 {
860     NTSTATUS ret;
861     SID_IDENTIFIER_AUTHORITY sia = {{ 1, 2, 3, 4, 5, 6 }};
862     PSID psid;
863 
864     if (!pRtlAllocateAndInitializeSid)
865     {
866         win_skip("RtlAllocateAndInitializeSid is not available\n");
867         return;
868     }
869 
870     ret = pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid);
871     ok(!ret, "RtlAllocateAndInitializeSid error %08x\n", ret);
872     ret = pRtlFreeSid(psid);
873     ok(!ret, "RtlFreeSid error %08x\n", ret);
874 
875     /* these tests crash on XP */
876     if (0)
877     {
878         pRtlAllocateAndInitializeSid(NULL, 0, 1, 2, 3, 4, 5, 6, 7, 8, &psid);
879         pRtlAllocateAndInitializeSid(&sia, 0, 1, 2, 3, 4, 5, 6, 7, 8, NULL);
880     }
881 
882     ret = pRtlAllocateAndInitializeSid(&sia, 9, 1, 2, 3, 4, 5, 6, 7, 8, &psid);
883     ok(ret == STATUS_INVALID_SID, "wrong error %08x\n", ret);
884 }
885 
886 static void test_RtlDeleteTimer(void)
887 {
888     NTSTATUS ret;
889 
890     if (!pRtlDeleteTimer)
891     {
892         win_skip("RtlDeleteTimer is not available\n");
893         return;
894     }
895 
896     ret = pRtlDeleteTimer(NULL, NULL, NULL);
897     ok(ret == STATUS_INVALID_PARAMETER_1 ||
898        ret == STATUS_INVALID_PARAMETER, /* W2K */
899        "expected STATUS_INVALID_PARAMETER_1 or STATUS_INVALID_PARAMETER, got %x\n", ret);
900 }
901 
902 static void test_RtlThreadErrorMode(void)
903 {
904     DWORD oldmode;
905     BOOL is_wow64;
906     DWORD mode;
907     NTSTATUS status;
908 
909     if (!pRtlGetThreadErrorMode || !pRtlSetThreadErrorMode)
910     {
911         win_skip("RtlGetThreadErrorMode and/or RtlSetThreadErrorMode not available\n");
912         return;
913     }
914 
915     if (!pIsWow64Process || !pIsWow64Process(GetCurrentProcess(), &is_wow64))
916         is_wow64 = FALSE;
917 
918     oldmode = pRtlGetThreadErrorMode();
919 
920     status = pRtlSetThreadErrorMode(0x70, &mode);
921     ok(status == STATUS_SUCCESS ||
922        status == STATUS_WAIT_1, /* Vista */
923        "RtlSetThreadErrorMode failed with error 0x%08x\n", status);
924     ok(mode == oldmode,
925        "RtlSetThreadErrorMode returned mode 0x%x, expected 0x%x\n",
926        mode, oldmode);
927     ok(pRtlGetThreadErrorMode() == 0x70,
928        "RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0x70);
929     if (!is_wow64)
930     {
931         ok(NtCurrentTeb()->HardErrorDisabled == 0x70,
932            "The TEB contains 0x%x, expected 0x%x\n",
933            NtCurrentTeb()->HardErrorDisabled, 0x70);
934     }
935 
936     status = pRtlSetThreadErrorMode(0, &mode);
937     ok(status == STATUS_SUCCESS ||
938        status == STATUS_WAIT_1, /* Vista */
939        "RtlSetThreadErrorMode failed with error 0x%08x\n", status);
940     ok(mode == 0x70,
941        "RtlSetThreadErrorMode returned mode 0x%x, expected 0x%x\n",
942        mode, 0x70);
943     ok(pRtlGetThreadErrorMode() == 0,
944        "RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0);
945     if (!is_wow64)
946     {
947         ok(NtCurrentTeb()->HardErrorDisabled == 0,
948            "The TEB contains 0x%x, expected 0x%x\n",
949            NtCurrentTeb()->HardErrorDisabled, 0);
950     }
951 
952     for (mode = 1; mode; mode <<= 1)
953     {
954         status = pRtlSetThreadErrorMode(mode, NULL);
955         if (mode & 0x70)
956             ok(status == STATUS_SUCCESS ||
957                status == STATUS_WAIT_1, /* Vista */
958                "RtlSetThreadErrorMode(%x,NULL) failed with error 0x%08x\n",
959                mode, status);
960         else
961             ok(status == STATUS_INVALID_PARAMETER_1,
962                "RtlSetThreadErrorMode(%x,NULL) returns 0x%08x, "
963                "expected STATUS_INVALID_PARAMETER_1\n",
964                mode, status);
965     }
966 
967     pRtlSetThreadErrorMode(oldmode, NULL);
968 }
969 
970 static void test_LdrProcessRelocationBlock(void)
971 {
972     IMAGE_BASE_RELOCATION *ret;
973     USHORT reloc;
974     DWORD addr32;
975     SHORT addr16;
976 
977     if(!pLdrProcessRelocationBlock) {
978         win_skip("LdrProcessRelocationBlock not available\n");
979         return;
980     }
981 
982     addr32 = 0x50005;
983     reloc = IMAGE_REL_BASED_HIGHLOW<<12;
984     ret = pLdrProcessRelocationBlock(&addr32, 1, &reloc, 0x500050);
985     ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1);
986     ok(addr32 == 0x550055, "addr32 = %x, expected 0x550055\n", addr32);
987 
988     addr16 = 0x505;
989     reloc = IMAGE_REL_BASED_HIGH<<12;
990     ret = pLdrProcessRelocationBlock(&addr16, 1, &reloc, 0x500060);
991     ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1);
992     ok(addr16 == 0x555, "addr16 = %x, expected 0x555\n", addr16);
993 
994     addr16 = 0x505;
995     reloc = IMAGE_REL_BASED_LOW<<12;
996     ret = pLdrProcessRelocationBlock(&addr16, 1, &reloc, 0x500060);
997     ok((USHORT*)ret == &reloc+1, "ret = %p, expected %p\n", ret, &reloc+1);
998     ok(addr16 == 0x565, "addr16 = %x, expected 0x565\n", addr16);
999 }
1000 
1001 static void test_RtlIpv4AddressToString(void)
1002 {
1003     CHAR buffer[20];
1004     CHAR *res;
1005     IN_ADDR ip;
1006     DWORD_PTR len;
1007 
1008     if (!pRtlIpv4AddressToStringA)
1009     {
1010         win_skip("RtlIpv4AddressToStringA not available\n");
1011         return;
1012     }
1013 
1014     ip.S_un.S_un_b.s_b1 = 1;
1015     ip.S_un.S_un_b.s_b2 = 2;
1016     ip.S_un.S_un_b.s_b3 = 3;
1017     ip.S_un.S_un_b.s_b4 = 4;
1018 
1019     memset(buffer, '#', sizeof(buffer) - 1);
1020     buffer[sizeof(buffer) -1] = 0;
1021     res = pRtlIpv4AddressToStringA(&ip, buffer);
1022     len = strlen(buffer);
1023     ok(res == (buffer + len), "got %p with '%s' (expected %p)\n", res, buffer, buffer + len);
1024 
1025     res = pRtlIpv4AddressToStringA(&ip, NULL);
1026     ok( (res == (char *)~0) ||
1027         broken(res == (char *)len),        /* XP and w2003 */
1028         "got %p (expected ~0)\n", res);
1029 
1030     if (0) {
1031         /* this crashes in windows */
1032         memset(buffer, '#', sizeof(buffer) - 1);
1033         buffer[sizeof(buffer) -1] = 0;
1034         res = pRtlIpv4AddressToStringA(NULL, buffer);
1035         trace("got %p with '%s'\n", res, buffer);
1036     }
1037 
1038     if (0) {
1039         /* this crashes in windows */
1040         res = pRtlIpv4AddressToStringA(NULL, NULL);
1041         trace("got %p\n", res);
1042     }
1043 }
1044 
1045 static void test_RtlIpv4AddressToStringEx(void)
1046 {
1047     CHAR ip_1234[] = "1.2.3.4";
1048     CHAR ip_1234_80[] = "1.2.3.4:80";
1049     LPSTR expect;
1050     CHAR buffer[30];
1051     NTSTATUS res;
1052     IN_ADDR ip;
1053     ULONG size;
1054     DWORD used;
1055     USHORT port;
1056 
1057     if (!pRtlIpv4AddressToStringExA)
1058     {
1059         win_skip("RtlIpv4AddressToStringExA not available\n");
1060         return;
1061     }
1062 
1063     ip.S_un.S_un_b.s_b1 = 1;
1064     ip.S_un.S_un_b.s_b2 = 2;
1065     ip.S_un.S_un_b.s_b3 = 3;
1066     ip.S_un.S_un_b.s_b4 = 4;
1067 
1068     port = htons(80);
1069     expect = ip_1234_80;
1070 
1071     size = sizeof(buffer);
1072     memset(buffer, '#', sizeof(buffer) - 1);
1073     buffer[sizeof(buffer) -1] = 0;
1074     res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1075     used = strlen(buffer);
1076     ok( (res == STATUS_SUCCESS) &&
1077         (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1078         "got 0x%x and size %d with '%s'\n", res, size, buffer);
1079 
1080     size = used + 1;
1081     memset(buffer, '#', sizeof(buffer) - 1);
1082     buffer[sizeof(buffer) -1] = 0;
1083     res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1084     ok( (res == STATUS_SUCCESS) &&
1085         (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1086         "got 0x%x and size %d with '%s'\n", res, size, buffer);
1087 
1088     size = used;
1089     memset(buffer, '#', sizeof(buffer) - 1);
1090     buffer[sizeof(buffer) -1] = 0;
1091     res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1092     ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1093         "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1094         res, size, buffer, used + 1);
1095 
1096     size = used - 1;
1097     memset(buffer, '#', sizeof(buffer) - 1);
1098     buffer[sizeof(buffer) -1] = 0;
1099     res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1100     ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1101         "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1102         res, size, buffer, used + 1);
1103 
1104 
1105     /* to get only the ip, use 0 as port */
1106     port = 0;
1107     expect = ip_1234;
1108 
1109     size = sizeof(buffer);
1110     memset(buffer, '#', sizeof(buffer) - 1);
1111     buffer[sizeof(buffer) -1] = 0;
1112     res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1113     used = strlen(buffer);
1114     ok( (res == STATUS_SUCCESS) &&
1115         (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1116         "got 0x%x and size %d with '%s'\n", res, size, buffer);
1117 
1118     size = used + 1;
1119     memset(buffer, '#', sizeof(buffer) - 1);
1120     buffer[sizeof(buffer) -1] = 0;
1121     res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1122     ok( (res == STATUS_SUCCESS) &&
1123         (size == strlen(expect) + 1) && !strcmp(buffer, expect),
1124         "got 0x%x and size %d with '%s'\n", res, size, buffer);
1125 
1126     size = used;
1127     memset(buffer, '#', sizeof(buffer) - 1);
1128     buffer[sizeof(buffer) -1] = 0;
1129     res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1130     ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1131         "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1132         res, size, buffer, used + 1);
1133 
1134     size = used - 1;
1135     memset(buffer, '#', sizeof(buffer) - 1);
1136     buffer[sizeof(buffer) -1] = 0;
1137     res = pRtlIpv4AddressToStringExA(&ip, port, buffer, &size);
1138     ok( (res == STATUS_INVALID_PARAMETER) && (size == used + 1),
1139         "got 0x%x and %d with '%s' (expected STATUS_INVALID_PARAMETER and %d)\n",
1140         res, size, buffer, used + 1);
1141 
1142 
1143     /* parameters are checked */
1144     memset(buffer, '#', sizeof(buffer) - 1);
1145     buffer[sizeof(buffer) -1] = 0;
1146     res = pRtlIpv4AddressToStringExA(&ip, 0, buffer, NULL);
1147     ok(res == STATUS_INVALID_PARAMETER,
1148         "got 0x%x with '%s' (expected STATUS_INVALID_PARAMETER)\n", res, buffer);
1149 
1150     size = sizeof(buffer);
1151     res = pRtlIpv4AddressToStringExA(&ip, 0, NULL, &size);
1152     ok( res == STATUS_INVALID_PARAMETER,
1153         "got 0x%x and size %d (expected STATUS_INVALID_PARAMETER)\n", res, size);
1154 
1155     size = sizeof(buffer);
1156     memset(buffer, '#', sizeof(buffer) - 1);
1157     buffer[sizeof(buffer) -1] = 0;
1158     res = pRtlIpv4AddressToStringExA(NULL, 0, buffer, &size);
1159     ok( res == STATUS_INVALID_PARAMETER,
1160         "got 0x%x and size %d with '%s' (expected STATUS_INVALID_PARAMETER)\n",
1161         res, size, buffer);
1162 }
1163 
1164 static struct
1165 {
1166     PCSTR address;
1167     NTSTATUS res;
1168     int terminator_offset;
1169     int ip[4];
1170     enum { normal_4, strict_diff_4 = 1, ex_fail_4 = 2 } flags;
1171     NTSTATUS res_strict;
1172     int terminator_offset_strict;
1173     int ip_strict[4];
1174 } ipv4_tests[] =
1175 {
1176     { "",                       STATUS_INVALID_PARAMETER,  0, { -1 } },
1177     { " ",                      STATUS_INVALID_PARAMETER,  0, { -1 } },
1178     { "1.1.1.1",                STATUS_SUCCESS,            7, {   1,   1,   1,   1 } },
1179     { "0.0.0.0",                STATUS_SUCCESS,            7, {   0,   0,   0,   0 } },
1180     { "255.255.255.255",        STATUS_SUCCESS,           15, { 255, 255, 255, 255 } },
1181     { "255.255.255.255:123",    STATUS_SUCCESS,           15, { 255, 255, 255, 255 } },
1182     { "255.255.255.256",        STATUS_INVALID_PARAMETER, 15, { -1 } },
1183     { "255.255.255.4294967295", STATUS_INVALID_PARAMETER, 22, { -1 } },
1184     { "255.255.255.4294967296", STATUS_INVALID_PARAMETER, 21, { -1 } },
1185     { "255.255.255.4294967297", STATUS_INVALID_PARAMETER, 21, { -1 } },
1186     { "a",                      STATUS_INVALID_PARAMETER,  0, { -1 } },
1187     { "1.1.1.0xaA",             STATUS_SUCCESS,           10, {   1,   1,   1, 170 }, strict_diff_4,
1188                                 STATUS_INVALID_PARAMETER,  8, { -1 } },
1189     { "1.1.1.0XaA",             STATUS_SUCCESS,           10, {   1,   1,   1, 170 }, strict_diff_4,
1190                                 STATUS_INVALID_PARAMETER,  8, { -1 } },
1191     { "1.1.1.0x",               STATUS_INVALID_PARAMETER,  8, { -1 } },
1192     { "1.1.1.0xff",             STATUS_SUCCESS,           10, {   1,   1,   1, 255 }, strict_diff_4,
1193                                 STATUS_INVALID_PARAMETER,  8, { -1 } },
1194     { "1.1.1.0x100",            STATUS_INVALID_PARAMETER, 11, { -1 }, strict_diff_4,
1195                                 STATUS_INVALID_PARAMETER,  8, { -1 } },
1196     { "1.1.1.0xffffffff",       STATUS_INVALID_PARAMETER, 16, { -1 }, strict_diff_4,
1197                                 STATUS_INVALID_PARAMETER,  8, { -1 } },
1198     { "1.1.1.0x100000000",      STATUS_INVALID_PARAMETER, 16, { -1, 0, 0, 0 }, strict_diff_4,
1199                                 STATUS_INVALID_PARAMETER,  8, { -1 } },
1200     { "1.1.1.010",              STATUS_SUCCESS,            9, {   1,   1,   1,   8 }, strict_diff_4,
1201                                 STATUS_INVALID_PARAMETER,  7, { -1 } },
1202     { "1.1.1.00",               STATUS_SUCCESS,            8, {   1,   1,   1,   0 }, strict_diff_4,
1203                                 STATUS_INVALID_PARAMETER,  7, { -1 } },
1204     { "1.1.1.007",              STATUS_SUCCESS,            9, {   1,   1,   1,   7 }, strict_diff_4,
1205                                 STATUS_INVALID_PARAMETER,  7, { -1 } },
1206     { "1.1.1.08",               STATUS_INVALID_PARAMETER,  7, { -1 } },
1207     { "1.1.1.008",              STATUS_SUCCESS,            8, {   1,   1,   1,   0 }, strict_diff_4 | ex_fail_4,
1208                                 STATUS_INVALID_PARAMETER,  7, { -1 } },
1209     { "1.1.1.0a",               STATUS_SUCCESS,            7, {   1,   1,   1,   0 }, ex_fail_4 },
1210     { "1.1.1.0o10",             STATUS_SUCCESS,            7, {   1,   1,   1,   0 }, ex_fail_4 },
1211     { "1.1.1.0b10",             STATUS_SUCCESS,            7, {   1,   1,   1,   0 }, ex_fail_4 },
1212     { "1.1.1.-2",               STATUS_INVALID_PARAMETER,  6, { -1 } },
1213     { "1",                      STATUS_SUCCESS,            1, {   0,   0,   0,   1 }, strict_diff_4,
1214                                 STATUS_INVALID_PARAMETER,  1, { -1 } },
1215     { "-1",                     STATUS_INVALID_PARAMETER,  0, { -1 } },
1216     { "203569230",              STATUS_SUCCESS,            9, {  12,  34,  56,  78 }, strict_diff_4,
1217                                 STATUS_INVALID_PARAMETER,  9, { -1 } },
1218     { "1.223756",               STATUS_SUCCESS,            8, {   1,   3, 106,  12 }, strict_diff_4,
1219                                 STATUS_INVALID_PARAMETER,  8, { -1 } },
1220     { "3.4.756",                STATUS_SUCCESS,            7, {   3,   4,   2, 244 }, strict_diff_4,
1221                                 STATUS_INVALID_PARAMETER,  7, { -1 } },
1222     { "3.4.756.1",              STATUS_INVALID_PARAMETER,  9, { -1 } },
1223     { "3.4.65536",              STATUS_INVALID_PARAMETER,  9, { -1 } },
1224     { "3.4.5.6.7",              STATUS_INVALID_PARAMETER,  7, { -1 } },
1225     { "3.4.5.+6",               STATUS_INVALID_PARAMETER,  6, { -1 } },
1226     { " 3.4.5.6",               STATUS_INVALID_PARAMETER,  0, { -1 } },
1227     { "\t3.4.5.6",              STATUS_INVALID_PARAMETER,  0, { -1 } },
1228     { "3.4.5.6 ",               STATUS_SUCCESS,            7, {   3,   4,   5,   6 }, ex_fail_4 },
1229     { "3. 4.5.6",               STATUS_INVALID_PARAMETER,  2, { -1 } },
1230     { ".",                      STATUS_INVALID_PARAMETER,  1, { -1 } },
1231     { "..",                     STATUS_INVALID_PARAMETER,  1, { -1 } },
1232     { "1.",                     STATUS_INVALID_PARAMETER,  2, { -1 } },
1233     { "1..",                    STATUS_INVALID_PARAMETER,  3, { -1 } },
1234     { ".1",                     STATUS_INVALID_PARAMETER,  1, { -1 } },
1235     { ".1.",                    STATUS_INVALID_PARAMETER,  1, { -1 } },
1236     { ".1.2.3",                 STATUS_INVALID_PARAMETER,  1, { -1 } },
1237     { "0.1.2.3",                STATUS_SUCCESS,            7, {   0,   1,   2,   3 } },
1238     { "0.1.2.3.",               STATUS_INVALID_PARAMETER,  7, { -1 } },
1239     { "[0.1.2.3]",              STATUS_INVALID_PARAMETER,  0, { -1 } },
1240     { "::1",                    STATUS_INVALID_PARAMETER,  0, { -1 } },
1241     { ":1",                     STATUS_INVALID_PARAMETER,  0, { -1 } },
1242 };
1243 const unsigned int ipv4_testcount = sizeof(ipv4_tests) / sizeof(ipv4_tests[0]);
1244 
1245 static void init_ip4(IN_ADDR* addr, const int src[4])
1246 {
1247     if (!src || src[0] == -1)
1248     {
1249         addr->S_un.S_addr = 0xabababab;
1250     }
1251     else
1252     {
1253         addr->S_un.S_un_b.s_b1 = src[0];
1254         addr->S_un.S_un_b.s_b2 = src[1];
1255         addr->S_un.S_un_b.s_b3 = src[2];
1256         addr->S_un.S_un_b.s_b4 = src[3];
1257     }
1258 }
1259 
1260 static void test_RtlIpv4StringToAddress(void)
1261 {
1262     NTSTATUS res;
1263     IN_ADDR ip, expected_ip;
1264     PCSTR terminator;
1265     CHAR dummy;
1266     unsigned int i;
1267 
1268     if (!pRtlIpv4StringToAddressA)
1269     {
1270         skip("RtlIpv4StringToAddress not available\n");
1271         return;
1272     }
1273 
1274     if (0)
1275     {
1276         /* leaving either parameter NULL crashes on Windows */
1277         res = pRtlIpv4StringToAddressA(NULL, FALSE, &terminator, &ip);
1278         res = pRtlIpv4StringToAddressA("1.1.1.1", FALSE, NULL, &ip);
1279         res = pRtlIpv4StringToAddressA("1.1.1.1", FALSE, &terminator, NULL);
1280         /* same for the wide char version */
1281         /*
1282         res = pRtlIpv4StringToAddressW(NULL, FALSE, &terminatorW, &ip);
1283         res = pRtlIpv4StringToAddressW(L"1.1.1.1", FALSE, NULL, &ip);
1284         res = pRtlIpv4StringToAddressW(L"1.1.1.1", FALSE, &terminatorW, NULL);
1285         */
1286     }
1287 
1288     for (i = 0; i < ipv4_testcount; i++)
1289     {
1290         /* non-strict */
1291         terminator = &dummy;
1292         ip.S_un.S_addr = 0xabababab;
1293         res = pRtlIpv4StringToAddressA(ipv4_tests[i].address, FALSE, &terminator, &ip);
1294         ok(res == ipv4_tests[i].res,
1295            "[%s] res = 0x%08x, expected 0x%08x\n",
1296            ipv4_tests[i].address, res, ipv4_tests[i].res);
1297         ok(terminator == ipv4_tests[i].address + ipv4_tests[i].terminator_offset,
1298            "[%s] terminator = %p, expected %p\n",
1299            ipv4_tests[i].address, terminator, ipv4_tests[i].address + ipv4_tests[i].terminator_offset);
1300 
1301         init_ip4(&expected_ip, ipv4_tests[i].ip);
1302         ok(ip.S_un.S_addr == expected_ip.S_un.S_addr,
1303            "[%s] ip = %08x, expected %08x\n",
1304            ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1305 
1306         if (!(ipv4_tests[i].flags & strict_diff_4))
1307         {
1308             ipv4_tests[i].res_strict = ipv4_tests[i].res;
1309             ipv4_tests[i].terminator_offset_strict = ipv4_tests[i].terminator_offset;
1310             ipv4_tests[i].ip_strict[0] = ipv4_tests[i].ip[0];
1311             ipv4_tests[i].ip_strict[1] = ipv4_tests[i].ip[1];
1312             ipv4_tests[i].ip_strict[2] = ipv4_tests[i].ip[2];
1313             ipv4_tests[i].ip_strict[3] = ipv4_tests[i].ip[3];
1314         }
1315         /* strict */
1316         terminator = &dummy;
1317         ip.S_un.S_addr = 0xabababab;
1318         res = pRtlIpv4StringToAddressA(ipv4_tests[i].address, TRUE, &terminator, &ip);
1319         ok(res == ipv4_tests[i].res_strict,
1320            "[%s] res = 0x%08x, expected 0x%08x\n",
1321            ipv4_tests[i].address, res, ipv4_tests[i].res_strict);
1322         ok(terminator == ipv4_tests[i].address + ipv4_tests[i].terminator_offset_strict,
1323            "[%s] terminator = %p, expected %p\n",
1324            ipv4_tests[i].address, terminator, ipv4_tests[i].address + ipv4_tests[i].terminator_offset_strict);
1325 
1326         init_ip4(&expected_ip, ipv4_tests[i].ip_strict);
1327         ok(ip.S_un.S_addr == expected_ip.S_un.S_addr,
1328            "[%s] ip = %08x, expected %08x\n",
1329            ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1330     }
1331 }
1332 
1333 static void test_RtlIpv4StringToAddressEx(void)
1334 {
1335     NTSTATUS res;
1336     IN_ADDR ip, expected_ip;
1337     USHORT port;
1338     static const struct
1339     {
1340         PCSTR address;
1341         NTSTATUS res;
1342         int ip[4];
1343         USHORT port;
1344     } ipv4_ex_tests[] =
1345     {
1346         { "",               STATUS_INVALID_PARAMETER,   { -1 },         0xdead },
1347         { " ",              STATUS_INVALID_PARAMETER,   { -1 },         0xdead },
1348         { "1.1.1.1:",       STATUS_INVALID_PARAMETER,   { 1, 1, 1, 1 }, 0xdead },
1349         { "1.1.1.1+",       STATUS_INVALID_PARAMETER,   { 1, 1, 1, 1 }, 0xdead },
1350         { "1.1.1.1:1",      STATUS_SUCCESS,             { 1, 1, 1, 1 }, 0x100 },
1351         { "256.1.1.1:1",    STATUS_INVALID_PARAMETER,   { -1 },         0xdead },
1352         { "-1.1.1.1:1",     STATUS_INVALID_PARAMETER,   { -1 },         0xdead },
1353         { "0.0.0.0:0",      STATUS_INVALID_PARAMETER,   { 0, 0, 0, 0 }, 0xdead },
1354         { "0.0.0.0:1",      STATUS_SUCCESS,             { 0, 0, 0, 0 }, 0x100 },
1355         { "1.2.3.4:65535",  STATUS_SUCCESS,             { 1, 2, 3, 4 }, 65535 },
1356         { "1.2.3.4:65536",  STATUS_INVALID_PARAMETER,   { 1, 2, 3, 4 }, 0xdead },
1357         { "1.2.3.4:0xffff", STATUS_SUCCESS,             { 1, 2, 3, 4 }, 65535 },
1358         { "1.2.3.4:0XfFfF", STATUS_SUCCESS,             { 1, 2, 3, 4 }, 65535 },
1359         { "1.2.3.4:011064", STATUS_SUCCESS,             { 1, 2, 3, 4 }, 0x3412 },
1360         { "1.2.3.4:1234a",  STATUS_INVALID_PARAMETER,   { 1, 2, 3, 4 }, 0xdead },
1361         { "1.2.3.4:1234+",  STATUS_INVALID_PARAMETER,   { 1, 2, 3, 4 }, 0xdead },
1362         { "1.2.3.4: 1234",  STATUS_INVALID_PARAMETER,   { 1, 2, 3, 4 }, 0xdead },
1363         { "1.2.3.4:\t1234", STATUS_INVALID_PARAMETER,   { 1, 2, 3, 4 }, 0xdead },
1364     };
1365     const unsigned int ipv4_ex_testcount = sizeof(ipv4_ex_tests) / sizeof(ipv4_ex_tests[0]);
1366     unsigned int i;
1367     BOOLEAN strict;
1368 
1369     if (!pRtlIpv4StringToAddressExA)
1370     {
1371         skip("RtlIpv4StringToAddressEx not available\n");
1372         return;
1373     }
1374 
1375     /* do not crash, and do not touch the ip / port. */
1376     ip.S_un.S_addr = 0xabababab;
1377     port = 0xdead;
1378     res = pRtlIpv4StringToAddressExA(NULL, FALSE, &ip, &port);
1379     ok(res == STATUS_INVALID_PARAMETER, "[null address] res = 0x%08x, expected 0x%08x\n",
1380        res, STATUS_INVALID_PARAMETER);
1381     ok(ip.S_un.S_addr == 0xabababab, "RtlIpv4StringToAddressExA should not touch the ip!, ip == %x\n", ip.S_un.S_addr);
1382     ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
1383 
1384     port = 0xdead;
1385     res = pRtlIpv4StringToAddressExA("1.1.1.1", FALSE, NULL, &port);
1386     ok(res == STATUS_INVALID_PARAMETER, "[null ip] res = 0x%08x, expected 0x%08x\n",
1387        res, STATUS_INVALID_PARAMETER);
1388     ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
1389 
1390     ip.S_un.S_addr = 0xabababab;
1391     port = 0xdead;
1392     res = pRtlIpv4StringToAddressExA("1.1.1.1", FALSE, &ip, NULL);
1393     ok(res == STATUS_INVALID_PARAMETER, "[null port] res = 0x%08x, expected 0x%08x\n",
1394        res, STATUS_INVALID_PARAMETER);
1395     ok(ip.S_un.S_addr == 0xabababab, "RtlIpv4StringToAddressExA should not touch the ip!, ip == %x\n", ip.S_un.S_addr);
1396     ok(port == 0xdead, "RtlIpv4StringToAddressExA should not touch the port!, port == %x\n", port);
1397 
1398     /* first we run the non-ex testcases on the ex function */
1399     for (i = 0; i < ipv4_testcount; i++)
1400     {
1401         NTSTATUS expect_res = (ipv4_tests[i].flags & ex_fail_4) ? STATUS_INVALID_PARAMETER : ipv4_tests[i].res;
1402 
1403         /* non-strict */
1404         port = 0xdead;
1405         ip.S_un.S_addr = 0xabababab;
1406         res = pRtlIpv4StringToAddressExA(ipv4_tests[i].address, FALSE, &ip, &port);
1407         ok(res == expect_res, "[%s] res = 0x%08x, expected 0x%08x\n",
1408            ipv4_tests[i].address, res, expect_res);
1409 
1410         init_ip4(&expected_ip, ipv4_tests[i].ip);
1411         ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
1412            ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1413 
1414         if (!(ipv4_tests[i].flags & strict_diff_4))
1415         {
1416             ipv4_tests[i].res_strict = ipv4_tests[i].res;
1417             ipv4_tests[i].terminator_offset_strict = ipv4_tests[i].terminator_offset;
1418             ipv4_tests[i].ip_strict[0] = ipv4_tests[i].ip[0];
1419             ipv4_tests[i].ip_strict[1] = ipv4_tests[i].ip[1];
1420             ipv4_tests[i].ip_strict[2] = ipv4_tests[i].ip[2];
1421             ipv4_tests[i].ip_strict[3] = ipv4_tests[i].ip[3];
1422         }
1423         /* strict */
1424         expect_res = (ipv4_tests[i].flags & ex_fail_4) ? STATUS_INVALID_PARAMETER : ipv4_tests[i].res_strict;
1425         port = 0xdead;
1426         ip.S_un.S_addr = 0xabababab;
1427         res = pRtlIpv4StringToAddressExA(ipv4_tests[i].address, TRUE, &ip, &port);
1428         ok(res == expect_res, "[%s] res = 0x%08x, expected 0x%08x\n",
1429            ipv4_tests[i].address, res, expect_res);
1430 
1431         init_ip4(&expected_ip, ipv4_tests[i].ip_strict);
1432         ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
1433            ipv4_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1434     }
1435 
1436 
1437     for (i = 0; i < ipv4_ex_testcount; i++)
1438     {
1439         /* Strict is only relevant for the ip address, so make sure that it does not influence the port */
1440         for (strict = 0; strict < 2; strict++)
1441         {
1442             ip.S_un.S_addr = 0xabababab;
1443             port = 0xdead;
1444             res = pRtlIpv4StringToAddressExA(ipv4_ex_tests[i].address, strict, &ip, &port);
1445             ok(res == ipv4_ex_tests[i].res, "[%s] res = 0x%08x, expected 0x%08x\n",
1446                ipv4_ex_tests[i].address, res, ipv4_ex_tests[i].res);
1447 
1448             init_ip4(&expected_ip, ipv4_ex_tests[i].ip);
1449             ok(ip.S_un.S_addr == expected_ip.S_un.S_addr, "[%s] ip = %08x, expected %08x\n",
1450                ipv4_ex_tests[i].address, ip.S_un.S_addr, expected_ip.S_un.S_addr);
1451             ok(port == ipv4_ex_tests[i].port, "[%s] port = %u, expected %u\n",
1452                ipv4_ex_tests[i].address, port, ipv4_ex_tests[i].port);
1453         }
1454     }
1455 }
1456 
1457 /* ipv6 addresses based on the set from https://github.com/beaugunderson/javascript-ipv6/tree/master/test/data */
1458 static const struct
1459 {
1460     PCSTR address;
1461     NTSTATUS res;
1462     int terminator_offset;
1463     int ip[8];
1464     /* win_broken: older versions of windows do not handle this correct
1465         ex_fail: Ex function does need the string to be terminated, non-Ex does not.
1466         ex_skip: test doesnt make sense for Ex (f.e. it's invalid for non-Ex but valid for Ex) */
1467     enum { normal_6, win_broken_6 = 1, ex_fail_6 = 2, ex_skip_6 = 4 } flags;
1468 } ipv6_tests[] =
1469 {
1470     { "0000:0000:0000:0000:0000:0000:0000:0000",        STATUS_SUCCESS,             39,
1471             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1472     { "0000:0000:0000:0000:0000:0000:0000:0001",        STATUS_SUCCESS,             39,
1473             { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1474     { "0:0:0:0:0:0:0:0",                                STATUS_SUCCESS,             15,
1475             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1476     { "0:0:0:0:0:0:0:1",                                STATUS_SUCCESS,             15,
1477             { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1478     { "0:0:0:0:0:0:0::",                                STATUS_SUCCESS,             13,
1479             { 0, 0, 0, 0, 0, 0, 0, 0 }, win_broken_6 },
1480     { "0:0:0:0:0:0:13.1.68.3",                          STATUS_SUCCESS,             21,
1481             { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1482     { "0:0:0:0:0:0::",                                  STATUS_SUCCESS,             13,
1483             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1484     { "0:0:0:0:0::",                                    STATUS_SUCCESS,             11,
1485             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1486     { "0:0:0:0:0:FFFF:129.144.52.38",                   STATUS_SUCCESS,             28,
1487             { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
1488     { "0::",                                            STATUS_SUCCESS,             3,
1489             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1490     { "0:1:2:3:4:5:6:7",                                STATUS_SUCCESS,             15,
1491             { 0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700 } },
1492     { "1080:0:0:0:8:800:200c:417a",                     STATUS_SUCCESS,             26,
1493             { 0x8010, 0, 0, 0, 0x800, 0x8, 0x0c20, 0x7a41 } },
1494     { "0:a:b:c:d:e:f::",                                STATUS_SUCCESS,             13,
1495             { 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00, 0 }, win_broken_6 },
1496     { "1111:2222:3333:4444:5555:6666:123.123.123.123",  STATUS_SUCCESS,             45,
1497             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1498     { "1111:2222:3333:4444:5555:6666:7777:8888",        STATUS_SUCCESS,             39,
1499             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1500     { "1111:2222:3333:4444:0x5555:6666:7777:8888",      STATUS_INVALID_PARAMETER,   21,
1501             { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1502     { "1111:2222:3333:4444:x555:6666:7777:8888",        STATUS_INVALID_PARAMETER,   20,
1503             { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1504     { "1111:2222:3333:4444:0r5555:6666:7777:8888",      STATUS_INVALID_PARAMETER,   21,
1505             { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1506     { "1111:2222:3333:4444:r5555:6666:7777:8888",       STATUS_INVALID_PARAMETER,   20,
1507             { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1508     { "1111:2222:3333:4444:5555:6666:7777::",           STATUS_SUCCESS,             34,
1509             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0 }, win_broken_6 },
1510     { "1111:2222:3333:4444:5555:6666::",                STATUS_SUCCESS,             31,
1511             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0 } },
1512     { "1111:2222:3333:4444:5555:6666::8888",            STATUS_SUCCESS,             35,
1513             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0x8888 } },
1514     { "1111:2222:3333:4444:5555::",                     STATUS_SUCCESS,             26,
1515             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0 } },
1516     { "1111:2222:3333:4444:5555::123.123.123.123",      STATUS_SUCCESS,             41,
1517             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7b7b, 0x7b7b } },
1518     { "1111:2222:3333:4444:5555::0x1.123.123.123",      STATUS_SUCCESS,             27,
1519             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x100 }, ex_fail_6 },
1520     { "1111:2222:3333:4444:5555::0x88",                 STATUS_SUCCESS,             27,
1521             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800 }, ex_fail_6 },
1522     { "1111:2222:3333:4444:5555::0X88",                 STATUS_SUCCESS,             27,
1523             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800 }, ex_fail_6 },
1524     { "1111:2222:3333:4444:5555::0X",                   STATUS_SUCCESS,             27,
1525             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0 }, ex_fail_6 },
1526     { "1111:2222:3333:4444:5555::0X88:7777",            STATUS_SUCCESS,             27,
1527             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8800 }, ex_fail_6 },
1528     { "1111:2222:3333:4444:5555::0x8888",               STATUS_SUCCESS,             27,
1529             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888 }, ex_fail_6 },
1530     { "1111:2222:3333:4444:5555::08888",                STATUS_INVALID_PARAMETER,   31,
1531             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0xabab, 0xabab, 0xabab } },
1532     { "1111:2222:3333:4444:5555::fffff",                STATUS_INVALID_PARAMETER,   31,
1533             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0xabab, 0xabab, 0xabab } },
1534     { "1111:2222:3333:4444::fffff",                     STATUS_INVALID_PARAMETER,   26,
1535             { 0x1111, 0x2222, 0x3333, 0x4444, 0xabab, 0xabab, 0xabab, 0xabab } },
1536     { "1111:2222:3333::fffff",                          STATUS_INVALID_PARAMETER,   21,
1537             { 0x1111, 0x2222, 0x3333, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1538     { "1111:2222:3333:4444:5555::7777:8888",            STATUS_SUCCESS,             35,
1539             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7777, 0x8888 } },
1540     { "1111:2222:3333:4444:5555::8888",                 STATUS_SUCCESS,             30,
1541             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888 } },
1542     { "1111::",                                         STATUS_SUCCESS,             6,
1543             { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1544     { "1111::123.123.123.123",                          STATUS_SUCCESS,             21,
1545             { 0x1111, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1546     { "1111::3333:4444:5555:6666:123.123.123.123",      STATUS_SUCCESS,             41,
1547             { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1548     { "1111::3333:4444:5555:6666:7777:8888",            STATUS_SUCCESS,             35,
1549             { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1550     { "1111::4444:5555:6666:123.123.123.123",           STATUS_SUCCESS,             36,
1551             { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1552     { "1111::4444:5555:6666:7777:8888",                 STATUS_SUCCESS,             30,
1553             { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1554     { "1111::5555:6666:123.123.123.123",                STATUS_SUCCESS,             31,
1555             { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1556     { "1111::5555:6666:7777:8888",                      STATUS_SUCCESS,             25,
1557             { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7777, 0x8888 } },
1558     { "1111::6666:123.123.123.123",                     STATUS_SUCCESS,             26,
1559             { 0x1111, 0, 0, 0, 0, 0x6666, 0x7b7b, 0x7b7b } },
1560     { "1111::6666:7777:8888",                           STATUS_SUCCESS,             20,
1561             { 0x1111, 0, 0, 0, 0, 0x6666, 0x7777, 0x8888 } },
1562     { "1111::7777:8888",                                STATUS_SUCCESS,             15,
1563             { 0x1111, 0, 0, 0, 0, 0, 0x7777, 0x8888 } },
1564     { "1111::8888",                                     STATUS_SUCCESS,             10,
1565             { 0x1111, 0, 0, 0, 0, 0, 0, 0x8888 } },
1566     { "1:2:3:4:5:6:1.2.3.4",                            STATUS_SUCCESS,             19,
1567             { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x201, 0x403 } },
1568     { "1:2:3:4:5:6:7:8",                                STATUS_SUCCESS,             15,
1569             { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800 } },
1570     { "1:2:3:4:5:6::",                                  STATUS_SUCCESS,             13,
1571             { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0 } },
1572     { "1:2:3:4:5:6::8",                                 STATUS_SUCCESS,             14,
1573             { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0x800 } },
1574     { "2001:0000:1234:0000:0000:C1C0:ABCD:0876",        STATUS_SUCCESS,             39,
1575             { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 } },
1576     { "2001:0000:4136:e378:8000:63bf:3fff:fdd2",        STATUS_SUCCESS,             39,
1577             { 0x120, 0, 0x3641, 0x78e3, 0x80, 0xbf63, 0xff3f, 0xd2fd } },
1578     { "2001:0db8:0:0:0:0:1428:57ab",                    STATUS_SUCCESS,             27,
1579             { 0x120, 0xb80d, 0, 0, 0, 0, 0x2814, 0xab57 } },
1580     { "2001:0db8:1234:ffff:ffff:ffff:ffff:ffff",        STATUS_SUCCESS,             39,
1581             { 0x120, 0xb80d, 0x3412, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1582     { "2001::CE49:7601:2CAD:DFFF:7C94:FFFE",            STATUS_SUCCESS,             35,
1583             { 0x120, 0, 0x49ce, 0x176, 0xad2c, 0xffdf, 0x947c, 0xfeff } },
1584     { "2001:db8:85a3::8a2e:370:7334",                   STATUS_SUCCESS,             28,
1585             { 0x120, 0xb80d, 0xa385, 0, 0, 0x2e8a, 0x7003, 0x3473 } },
1586     { "3ffe:0b00:0000:0000:0001:0000:0000:000a",        STATUS_SUCCESS,             39,
1587             { 0xfe3f, 0xb, 0, 0, 0x100, 0, 0, 0xa00 } },
1588     { "::",                                             STATUS_SUCCESS,             2,
1589             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1590     { "::%16",                                          STATUS_SUCCESS,             2,
1591             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1592     { "::/16",                                          STATUS_SUCCESS,             2,
1593             { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1594     { "::0",                                            STATUS_SUCCESS,             3,
1595             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1596     { "::0:0",                                          STATUS_SUCCESS,             5,
1597             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1598     { "::0:0:0",                                        STATUS_SUCCESS,             7,
1599             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1600     { "::0:0:0:0",                                      STATUS_SUCCESS,             9,
1601             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1602     { "::0:0:0:0:0",                                    STATUS_SUCCESS,             11,
1603             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1604     { "::0:0:0:0:0:0",                                  STATUS_SUCCESS,             13,
1605             { 0, 0, 0, 0, 0, 0, 0, 0 } },
1606     /* this one and the next one are incorrectly parsed by windows,
1607         it adds one zero too many in front, cutting off the last digit. */
1608     { "::0:0:0:0:0:0:0",                                STATUS_SUCCESS,             13,
1609             { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1610     { "::0:a:b:c:d:e:f",                                STATUS_SUCCESS,             13,
1611             { 0, 0, 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00 }, ex_fail_6 },
1612     { "::123.123.123.123",                              STATUS_SUCCESS,             17,
1613             { 0, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1614     { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",        STATUS_SUCCESS,             39,
1615             { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1616 
1617     { "':10.0.0.1",                                     STATUS_INVALID_PARAMETER,   0,
1618             { -1 } },
1619     { "-1",                                             STATUS_INVALID_PARAMETER,   0,
1620             { -1 } },
1621     { "02001:0000:1234:0000:0000:C1C0:ABCD:0876",       STATUS_INVALID_PARAMETER,   -1,
1622             { -1 } },
1623     { "2001:00000:1234:0000:0000:C1C0:ABCD:0876",       STATUS_INVALID_PARAMETER,   -1,
1624             { 0x120, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1625     { "2001:0000:01234:0000:0000:C1C0:ABCD:0876",       STATUS_INVALID_PARAMETER,   -1,
1626             { 0x120, 0, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1627     { "1.2.3.4",                                        STATUS_INVALID_PARAMETER,   7,
1628             { 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1629     { "1.2.3.4:1111::5555",                             STATUS_INVALID_PARAMETER,   7,
1630             { 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1631     { "1.2.3.4::5555",                                  STATUS_INVALID_PARAMETER,   7,
1632             { 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1633     { "11112222:3333:4444:5555:6666:1.2.3.4",           STATUS_INVALID_PARAMETER,   -1,
1634             { -1 } },
1635     { "11112222:3333:4444:5555:6666:7777:8888",         STATUS_INVALID_PARAMETER,   -1,
1636             { -1 } },
1637     { "1111",                                           STATUS_INVALID_PARAMETER,   4,
1638             { -1 } },
1639     { "1111:22223333:4444:5555:6666:1.2.3.4",           STATUS_INVALID_PARAMETER,   -1,
1640             { 0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1641     { "1111:22223333:4444:5555:6666:7777:8888",         STATUS_INVALID_PARAMETER,   -1,
1642             { 0x1111, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1643     { "1111:2222:",                                     STATUS_INVALID_PARAMETER,   10,
1644             { 0x1111, 0x2222, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1645     { "1111:2222:1.2.3.4",                              STATUS_INVALID_PARAMETER,   17,
1646             { 0x1111, 0x2222, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab } },
1647     { "1111:2222:3333",                                 STATUS_INVALID_PARAMETER,   14,
1648             { 0x1111, 0x2222, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1649     { "1111:2222:3333:4444:5555:6666:7777:1.2.3.4",     STATUS_SUCCESS,             36,
1650             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x100 }, ex_fail_6 },
1651     { "1111:2222:3333:4444:5555:6666:7777:8888:",       STATUS_SUCCESS,             39,
1652             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 }, ex_fail_6 },
1653     { "1111:2222:3333:4444:5555:6666:7777:8888:1.2.3.4",STATUS_SUCCESS,             39,
1654             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 }, ex_fail_6 },
1655     { "1111:2222:3333:4444:5555:6666:7777:8888:9999",   STATUS_SUCCESS,             39,
1656             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 }, ex_fail_6 },
1657     { "1111:2222:::",                                   STATUS_SUCCESS,             11,
1658             { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1659     { "1111::5555:",                                    STATUS_INVALID_PARAMETER,   11,
1660             { 0x1111, 0x5555, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1661     { "1111::3333:4444:5555:6666:7777::",               STATUS_SUCCESS,             30,
1662             { 0x1111, 0, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777 }, ex_fail_6 },
1663     { "1111:2222:::4444:5555:6666:1.2.3.4",             STATUS_SUCCESS,             11,
1664             { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1665     { "1111::3333::5555:6666:1.2.3.4",                  STATUS_SUCCESS,             10,
1666             { 0x1111, 0, 0, 0, 0, 0, 0, 0x3333 }, ex_fail_6 },
1667     { "12345::6:7:8",                                   STATUS_INVALID_PARAMETER,   -1,
1668             { -1 } },
1669     { "1::1.2.256.4",                                   STATUS_INVALID_PARAMETER,   -1,
1670             { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1671     { "1::1.2.3.256",                                   STATUS_INVALID_PARAMETER,   12,
1672             { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1673     { "1::1.2.3.300",                                   STATUS_INVALID_PARAMETER,   12,
1674             { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1675     { "1::1.2::1",                                      STATUS_INVALID_PARAMETER,   6,
1676             { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1677     { "1::1.2.3.4::1",                                  STATUS_SUCCESS,             10,
1678             { 0x100, 0, 0, 0, 0, 0, 0x201, 0x403 }, ex_fail_6 },
1679     { "1::1.",                                          STATUS_INVALID_PARAMETER,   5,
1680             { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1681     { "1::1.2",                                         STATUS_INVALID_PARAMETER,   6,
1682             { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1683     { "1::1.2.",                                        STATUS_INVALID_PARAMETER,   7,
1684             { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1685     { "1::1.2.3",                                       STATUS_INVALID_PARAMETER,   8,
1686             { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1687     { "1::1.2.3.",                                      STATUS_INVALID_PARAMETER,   9,
1688             { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1689     { "1::1.2.3.4",                                     STATUS_SUCCESS,             10,
1690             { 0x100, 0, 0, 0, 0, 0, 0x201, 0x403 } },
1691     { "1::1.2.3.900",                                   STATUS_INVALID_PARAMETER,   12,
1692             { 0x100, 0x201, 0xab03, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1693     { "1::1.2.300.4",                                   STATUS_INVALID_PARAMETER,   -1,
1694             { 0x100, 0x201, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1695     { "1::1.256.3.4",                                   STATUS_INVALID_PARAMETER,   -1,
1696             { 0x100, 0xab01, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1697     { "1::256.2.3.4",                                   STATUS_INVALID_PARAMETER,   -1,
1698             { 0x100, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1699     { "1::2::3",                                        STATUS_SUCCESS,             4,
1700             { 0x100, 0, 0, 0, 0, 0, 0, 0x200 }, ex_fail_6 },
1701     { "2001:0000:1234: 0000:0000:C1C0:ABCD:0876",       STATUS_INVALID_PARAMETER,   15,
1702             { 0x120, 0, 0x3412, 0xabab, 0xabab, 0xabab, 0xabab, 0xabab } },
1703     { "2001:0000:1234:0000:0000:C1C0:ABCD:0876  0",     STATUS_SUCCESS,             39,
1704             { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 }, ex_fail_6 },
1705     { "2001:1:1:1:1:1:255Z255X255Y255",                 STATUS_INVALID_PARAMETER,   18,
1706             { 0x120, 0x100, 0x100, 0x100, 0x100, 0x100, 0xabab, 0xabab } },
1707     { "2001::FFD3::57ab",                               STATUS_SUCCESS,             10,
1708             { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff }, ex_fail_6 },
1709     { ":",                                              STATUS_INVALID_PARAMETER,   0,
1710             { -1 } },
1711     { ":1111:2222:3333:4444:5555:6666:1.2.3.4",         STATUS_INVALID_PARAMETER,   0,
1712             { -1 } },
1713     { ":1111:2222:3333:4444:5555:6666:7777:8888",       STATUS_INVALID_PARAMETER,   0,
1714             { -1 } },
1715     { ":1111::",                                        STATUS_INVALID_PARAMETER,   0,
1716             { -1 } },
1717     { "::-1",                                           STATUS_SUCCESS,             2,
1718             { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1719     { "::.",                                            STATUS_SUCCESS,             2,
1720             { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1721     { "::..",                                           STATUS_SUCCESS,             2,
1722             { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1723     { "::...",                                          STATUS_SUCCESS,             2,
1724             { 0, 0, 0, 0, 0, 0, 0, 0 }, ex_fail_6 },
1725     { "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:1.2.3.4",          STATUS_INVALID_PARAMETER,   0,
1726             { -1 } },
1727     { "[::]",                                           STATUS_INVALID_PARAMETER,   0,
1728             { -1 }, ex_skip_6 },
1729 };
1730 const unsigned int ipv6_testcount = sizeof(ipv6_tests) / sizeof(ipv6_tests[0]);
1731 
1732 static void init_ip6(IN6_ADDR* addr, const int src[8])
1733 {
1734     unsigned int j;
1735     if (!src || src[0] == -1)
1736     {
1737         for (j = 0; j < 8; ++j)
1738             addr->s6_words[j] = 0xabab;
1739     }
1740     else
1741     {
1742         for (j = 0; j < 8; ++j)
1743             addr->s6_words[j] = src[j];
1744     }
1745 }
1746 
1747 static void test_RtlIpv6AddressToString(void)
1748 {
1749     CHAR buffer[50];
1750     LPCSTR result;
1751     IN6_ADDR ip;
1752     DWORD_PTR len;
1753     struct
1754     {
1755         PCSTR address;
1756         int ip[8];
1757     } tests[] =
1758     {
1759         /* ipv4 addresses & ISATAP addresses */
1760         { "::13.1.68.3",                                { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1761         { "::ffff:13.1.68.3",                           { 0, 0, 0, 0, 0, 0xffff, 0x10d, 0x344 } },
1762         { "::feff:d01:4403",                            { 0, 0, 0, 0, 0, 0xfffe, 0x10d, 0x344 } },
1763         { "::fffe:d01:4403",                            { 0, 0, 0, 0, 0, 0xfeff, 0x10d, 0x344 } },
1764         { "::100:d01:4403",                             { 0, 0, 0, 0, 0, 1, 0x10d, 0x344 } },
1765         { "::1:d01:4403",                               { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1766         { "::ffff:0:4403",                              { 0, 0, 0, 0, 0, 0xffff, 0, 0x344 } },
1767         { "::ffff:13.1.0.0",                            { 0, 0, 0, 0, 0, 0xffff, 0x10d, 0 } },
1768         { "::ffff:0:0",                                 { 0, 0, 0, 0, 0, 0xffff, 0, 0 } },
1769         { "::ffff:0:13.1.68.3",                         { 0, 0, 0, 0, 0xffff, 0, 0x10d, 0x344 } },
1770         { "::ffff:ffff:d01:4403",                       { 0, 0, 0, 0, 0xffff, 0xffff, 0x10d, 0x344 } },
1771         { "::ffff:0:0:d01:4403",                        { 0, 0, 0, 0xffff, 0, 0, 0x10d, 0x344 } },
1772         { "::ffff:255.255.255.255",                     { 0, 0, 0, 0, 0, 0xffff, 0xffff, 0xffff } },
1773         { "::ffff:129.144.52.38",                       { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
1774         { "::5efe:129.144.52.38",                       { 0, 0, 0, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
1775         { "1111:2222:3333:4444:0:5efe:129.144.52.38",   { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1776         { "1111:2222:3333::5efe:129.144.52.38",         { 0x1111, 0x2222, 0x3333, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
1777         { "1111:2222::5efe:129.144.52.38",              { 0x1111, 0x2222, 0, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
1778         { "1111::5efe:129.144.52.38",                   { 0x1111, 0, 0, 0, 0, 0xfe5e, 0x9081, 0x2634 } },
1779         { "::200:5efe:129.144.52.38",                   { 0, 0, 0, 0, 2, 0xfe5e, 0x9081, 0x2634 } },
1780         { "::100:5efe:8190:3426",                       { 0, 0, 0, 0, 1, 0xfe5e, 0x9081, 0x2634 } },
1781         /* 'normal' addresses */
1782         { "::1",                                        { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1783         { "0:1:2:3:4:5:6:7",                            { 0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700 } },
1784         { "1080::8:800:200c:417a",                      { 0x8010, 0, 0, 0, 0x800, 0x8, 0x0c20, 0x7a41 } },
1785         { "1111:2222:3333:4444:5555:6666:7b7b:7b7b",    { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1786         { "1111:2222:3333:4444:5555:6666:7777:8888",    { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1787         { "1111:2222:3333:4444:5555:6666::",            { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0 } },
1788         { "1111:2222:3333:4444:5555:6666:0:8888",       { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0, 0x8888 } },
1789         { "1111:2222:3333:4444:5555::",                 { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0 } },
1790         { "1111:2222:3333:4444:5555:0:7b7b:7b7b",       { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7b7b, 0x7b7b } },
1791         { "1111:2222:3333:4444:5555:0:7777:8888",       { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0x7777, 0x8888 } },
1792         { "1111:2222:3333:4444:5555::8888",             { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0, 0, 0x8888 } },
1793         { "1111::",                                     { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1794         { "1111::7b7b:7b7b",                            { 0x1111, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1795         { "1111:0:3333:4444:5555:6666:7b7b:7b7b",       { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1796         { "1111:0:3333:4444:5555:6666:7777:8888",       { 0x1111, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1797         { "1111::4444:5555:6666:7b7b:7b7b",             { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1798         { "1111::4444:5555:6666:7777:8888",             { 0x1111, 0, 0, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1799         { "1111::5555:6666:7b7b:7b7b",                  { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1800         { "1111::5555:6666:7777:8888",                  { 0x1111, 0, 0, 0, 0x5555, 0x6666, 0x7777, 0x8888 } },
1801         { "1111::6666:7b7b:7b7b",                       { 0x1111, 0, 0, 0, 0, 0x6666, 0x7b7b, 0x7b7b } },
1802         { "1111::6666:7777:8888",                       { 0x1111, 0, 0, 0, 0, 0x6666, 0x7777, 0x8888 } },
1803         { "1111::7777:8888",                            { 0x1111, 0, 0, 0, 0, 0, 0x7777, 0x8888 } },
1804         { "1111::8888",                                 { 0x1111, 0, 0, 0, 0, 0, 0, 0x8888 } },
1805         { "1:2:3:4:5:6:102:304",                        { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x201, 0x403 } },
1806         { "1:2:3:4:5:6:7:8",                            { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x800 } },
1807         { "1:2:3:4:5:6::",                              { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0 } },
1808         { "1:2:3:4:5:6:0:8",                            { 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0, 0x800 } },
1809         { "2001:0:1234::c1c0:abcd:876",                 { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 } },
1810         { "2001:0:4136:e378:8000:63bf:3fff:fdd2",       { 0x120, 0, 0x3641, 0x78e3, 0x80, 0xbf63, 0xff3f, 0xd2fd } },
1811         { "2001:db8::1428:57ab",                        { 0x120, 0xb80d, 0, 0, 0, 0, 0x2814, 0xab57 } },
1812         { "2001:db8:1234:ffff:ffff:ffff:ffff:ffff",     { 0x120, 0xb80d, 0x3412, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1813         { "2001:0:ce49:7601:2cad:dfff:7c94:fffe",       { 0x120, 0, 0x49ce, 0x176, 0xad2c, 0xffdf, 0x947c, 0xfeff } },
1814         { "2001:db8:85a3::8a2e:370:7334",               { 0x120, 0xb80d, 0xa385, 0, 0, 0x2e8a, 0x7003, 0x3473 } },
1815         { "3ffe:b00::1:0:0:a",                          { 0xfe3f, 0xb, 0, 0, 0x100, 0, 0, 0xa00 } },
1816         { "::a:b:c:d:e",                                { 0, 0, 0, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00 } },
1817         { "::123.123.123.123",                          { 0, 0, 0, 0, 0, 0, 0x7b7b, 0x7b7b } },
1818         { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",    { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } },
1819         { "1111:2222:3333:4444:5555:6666:7777:1",       { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x100 } },
1820         { "1111:2222:3333:4444:5555:6666:7777:8888",    { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888 } },
1821         { "1111:2222::",                                { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 } },
1822         { "1111::3333:4444:5555:6666:7777",             { 0x1111, 0, 0, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777 } },
1823         { "1111:2222::",                                { 0x1111, 0x2222, 0, 0, 0, 0, 0, 0 } },
1824         { "1111::3333",                                 { 0x1111, 0, 0, 0, 0, 0, 0, 0x3333 } },
1825         { "2001:0:1234::c1c0:abcd:876",                 { 0x120, 0, 0x3412, 0, 0, 0xc0c1, 0xcdab, 0x7608 } },
1826         { "2001::ffd3",                                 { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1827     };
1828     const size_t testcount = sizeof(tests) / sizeof(tests[0]);
1829     unsigned int i;
1830 
1831     if (!pRtlIpv6AddressToStringA)
1832     {
1833         skip("RtlIpv6AddressToStringA not available\n");
1834         return;
1835     }
1836 
1837     memset(buffer, '#', sizeof(buffer));
1838     buffer[sizeof(buffer)-1] = 0;
1839     memset(&ip, 0, sizeof(ip));
1840     result = pRtlIpv6AddressToStringA(&ip, buffer);
1841 
1842     len = strlen(buffer);
1843     ok(result == (buffer + len) && !strcmp(buffer, "::"),
1844        "got %p with '%s' (expected %p with '::')\n", result, buffer, buffer + len);
1845 
1846     result = pRtlIpv6AddressToStringA(&ip, NULL);
1847     ok(result == (LPCSTR)~0 || broken(result == (LPCSTR)len) /* WinXP / Win2k3 */,
1848        "got %p, expected %p\n", result, (LPCSTR)~0);
1849 
1850     for (i = 0; i < testcount; i++)
1851     {
1852         init_ip6(&ip, tests[i].ip);
1853         memset(buffer, '#', sizeof(buffer));
1854         buffer[sizeof(buffer)-1] = 0;
1855 
1856         result = pRtlIpv6AddressToStringA(&ip, buffer);
1857         len = strlen(buffer);
1858         ok(result == (buffer + len) && !strcmp(buffer, tests[i].address),
1859            "got %p with '%s' (expected %p with '%s')\n", result, buffer, buffer + len, tests[i].address);
1860 
1861         ok(buffer[45] == 0 || broken(buffer[45] != 0) /* WinXP / Win2k3 */,
1862            "expected data at buffer[45] to always be NULL\n");
1863         ok(buffer[46] == '#', "expected data at buffer[46] not to change\n");
1864     }
1865 }
1866 
1867 static void test_RtlIpv6AddressToStringEx(void)
1868 {
1869     CHAR buffer[70];
1870     NTSTATUS res;
1871     IN6_ADDR ip;
1872     ULONG len;
1873     struct
1874     {
1875         PCSTR address;
1876         ULONG scopeid;
1877         USHORT port;
1878         int ip[8];
1879     } tests[] =
1880     {
1881         /* ipv4 addresses & ISATAP addresses */
1882         { "::13.1.68.3",                                                0,          0, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1883         { "::13.1.68.3%1",                                              1,          0, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1884         { "::13.1.68.3%4294949819",                                     0xffffbbbb, 0, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1885         { "[::13.1.68.3%4294949819]:65518",                             0xffffbbbb, 0xeeff, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1886         { "[::13.1.68.3%4294949819]:256",                               0xffffbbbb, 1, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1887         { "[::13.1.68.3]:256",                                          0,          1, { 0, 0, 0, 0, 0, 0, 0x10d, 0x344 } },
1888 
1889         { "::1:d01:4403",                                               0,          0, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1890         { "::1:d01:4403%1",                                             1,          0, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1891         { "::1:d01:4403%4294949819",                                    0xffffbbbb, 0, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1892         { "[::1:d01:4403%4294949819]:65518",                            0xffffbbbb, 0xeeff, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1893         { "[::1:d01:4403%4294949819]:256",                              0xffffbbbb, 1, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1894         { "[::1:d01:4403]:256",                                         0,          1, { 0, 0, 0, 0, 0, 0x100, 0x10d, 0x344 } },
1895 
1896         { "1111:2222:3333:4444:0:5efe:129.144.52.38",                   0,          0, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1897         { "1111:2222:3333:4444:0:5efe:129.144.52.38%1",                 1,          0, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1898         { "1111:2222:3333:4444:0:5efe:129.144.52.38%4294949819",        0xffffbbbb, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1899         { "[1111:2222:3333:4444:0:5efe:129.144.52.38%4294949819]:65518",0xffffbbbb, 0xeeff, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1900         { "[1111:2222:3333:4444:0:5efe:129.144.52.38%4294949819]:256",  0xffffbbbb, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1901         { "[1111:2222:3333:4444:0:5efe:129.144.52.38]:256",             0,          1, { 0x1111, 0x2222, 0x3333, 0x4444, 0, 0xfe5e, 0x9081, 0x2634 } },
1902 
1903         { "::1",                                                        0,          0, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1904         { "::1%1",                                                      1,          0, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1905         { "::1%4294949819",                                             0xffffbbbb, 0, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1906         { "[::1%4294949819]:65518",                                     0xffffbbbb, 0xeeff, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1907         { "[::1%4294949819]:256",                                       0xffffbbbb, 1, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1908         { "[::1]:256",                                                  0,          1, { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
1909 
1910         { "1111:2222:3333:4444:5555:6666:7b7b:7b7b",                    0,          0, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1911         { "1111:2222:3333:4444:5555:6666:7b7b:7b7b%1",                  1,          0, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1912         { "1111:2222:3333:4444:5555:6666:7b7b:7b7b%4294949819",         0xffffbbbb, 0, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1913         { "[1111:2222:3333:4444:5555:6666:7b7b:7b7b%4294949819]:65518", 0xffffbbbb, 0xeeff, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1914         { "[1111:2222:3333:4444:5555:6666:7b7b:7b7b%4294949819]:256",   0xffffbbbb, 1, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1915         { "[1111:2222:3333:4444:5555:6666:7b7b:7b7b]:256",              0,          1, { 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7b7b, 0x7b7b } },
1916 
1917         { "1111::",                                                     0,          0, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1918         { "1111::%1",                                                   1,          0, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1919         { "1111::%4294949819",                                          0xffffbbbb, 0, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1920         { "[1111::%4294949819]:65518",                                  0xffffbbbb, 0xeeff, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1921         { "[1111::%4294949819]:256",                                    0xffffbbbb, 1, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1922         { "[1111::]:256",                                               0,          1, { 0x1111, 0, 0, 0, 0, 0, 0, 0 } },
1923 
1924         { "2001::ffd3",                                                 0,          0, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1925         { "2001::ffd3%1",                                               1,          0, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1926         { "2001::ffd3%4294949819",                                      0xffffbbbb, 0, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1927         { "[2001::ffd3%4294949819]:65518",                              0xffffbbbb, 0xeeff, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1928         { "[2001::ffd3%4294949819]:256",                                0xffffbbbb, 1, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1929         { "[2001::ffd3]:256",                                           0,          1, { 0x120, 0, 0, 0, 0, 0, 0, 0xd3ff } },
1930     };
1931     const size_t testcount = sizeof(tests) / sizeof(tests[0]);
1932     unsigned int i;
1933 
1934     if (!pRtlIpv6AddressToStringExA)
1935     {
1936         skip("RtlIpv6AddressToStringExA not available\n");
1937         return;
1938     }
1939 
1940     memset(buffer, '#', sizeof(buffer));
1941     buffer[sizeof(buffer)-1] = 0;
1942     memset(&ip, 0, sizeof(ip));
1943     len = sizeof(buffer);
1944     res = pRtlIpv6AddressToStringExA(&ip, 0, 0, buffer, &len);
1945 
1946     ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
1947     ok(len == 3 && !strcmp(buffer, "::"),
1948         "got len %d with '%s' (expected 3 with '::')\n", len, buffer);
1949 
1950     memset(buffer, '#', sizeof(buffer));
1951     buffer[sizeof(buffer)-1] = 0;
1952 
1953     len = sizeof(buffer);
1954     res = pRtlIpv6AddressToStringExA(NULL, 0, 0, buffer, &len);
1955     ok(res == STATUS_INVALID_PARAMETER, "[null ip] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
1956 
1957     len = sizeof(buffer);
1958     res = pRtlIpv6AddressToStringExA(&ip, 0, 0, NULL, &len);
1959     ok(res == STATUS_INVALID_PARAMETER, "[null buffer] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
1960 
1961     res = pRtlIpv6AddressToStringExA(&ip, 0, 0, buffer, NULL);
1962     ok(res == STATUS_INVALID_PARAMETER, "[null length] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
1963 
1964     len = 2;
1965     memset(buffer, '#', sizeof(buffer));
1966     buffer[sizeof(buffer)-1] = 0;
1967     res = pRtlIpv6AddressToStringExA(&ip, 0, 0, buffer, &len);
1968     ok(res == STATUS_INVALID_PARAMETER, "[null length] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
1969     ok(buffer[0] == '#', "got first char %c (expected '#')\n", buffer[0]);
1970     ok(len == 3, "got len %d (expected len 3)\n", len);
1971 
1972     for (i = 0; i < testcount; i++)
1973     {
1974         init_ip6(&ip, tests[i].ip);
1975         len = sizeof(buffer);
1976         memset(buffer, '#', sizeof(buffer));
1977         buffer[sizeof(buffer)-1] = 0;
1978 
1979         res = pRtlIpv6AddressToStringExA(&ip, tests[i].scopeid, tests[i].port, buffer, &len);
1980 
1981         ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
1982         ok(len == (strlen(tests[i].address) + 1) && !strcmp(buffer, tests[i].address),
1983            "got len %d with '%s' (expected %d with '%s')\n", len, buffer, (int)strlen(tests[i].address), tests[i].address);
1984     }
1985 }
1986 
1987 static void compare_RtlIpv6StringToAddressW(PCSTR name_a, int terminator_offset_a,
1988                                             const struct in6_addr *addr_a, NTSTATUS res_a)
1989 {
1990     WCHAR name[512];
1991     NTSTATUS res;
1992     IN6_ADDR ip;
1993     PCWSTR terminator;
1994 
1995     if (!pRtlIpv6StringToAddressW)
1996         return;
1997 
1998     pRtlMultiByteToUnicodeN(name, sizeof(name), NULL, name_a, strlen(name_a) + 1);
1999 
2000     init_ip6(&ip, NULL);
2001     terminator = (void *)0xdeadbeef;
2002     res = pRtlIpv6StringToAddressW(name, &terminator, &ip);
2003     ok(res == res_a, "[W:%s] res = 0x%08x, expected 0x%08x\n", name_a, res, res_a);
2004 
2005     if (terminator_offset_a < 0)
2006     {
2007         ok(terminator == (void *)0xdeadbeef,
2008            "[W:%s] terminator = %p, expected it not to change\n",
2009            name_a, terminator);
2010     }
2011     else
2012     {
2013         ok(terminator == name + terminator_offset_a,
2014            "[W:%s] terminator = %p, expected %p\n",
2015            name_a, terminator, name + terminator_offset_a);
2016     }
2017 
2018     ok(!memcmp(&ip, addr_a, sizeof(ip)),
2019        "[W:%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2020        name_a,
2021        ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2022        ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2023        addr_a->s6_words[0], addr_a->s6_words[1], addr_a->s6_words[2], addr_a->s6_words[3],
2024        addr_a->s6_words[4], addr_a->s6_words[5], addr_a->s6_words[6], addr_a->s6_words[7]);
2025 }
2026 
2027 static void test_RtlIpv6StringToAddress(void)
2028 {
2029     NTSTATUS res;
2030     IN6_ADDR ip, expected_ip;
2031     PCSTR terminator;
2032     unsigned int i;
2033 
2034     if (!pRtlIpv6StringToAddressW)
2035     {
2036         skip("RtlIpv6StringToAddressW not available\n");
2037         /* we can continue, just not test W */
2038     }
2039 
2040     if (!pRtlIpv6StringToAddressA)
2041     {
2042         skip("RtlIpv6StringToAddressA not available\n");
2043         return; /* all tests are centered around A, we cannot continue */
2044     }
2045 
2046     res = pRtlIpv6StringToAddressA("::", &terminator, &ip);
2047     ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
2048     if (0)
2049     {
2050         /* any of these crash */
2051         res = pRtlIpv6StringToAddressA(NULL, &terminator, &ip);
2052         ok(res == STATUS_INVALID_PARAMETER, "[null string] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2053         res = pRtlIpv6StringToAddressA("::", NULL, &ip);
2054         ok(res == STATUS_INVALID_PARAMETER, "[null terminator] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2055         res = pRtlIpv6StringToAddressA("::", &terminator, NULL);
2056         ok(res == STATUS_INVALID_PARAMETER, "[null result] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2057     }
2058 
2059     /* sanity check */
2060     ok(sizeof(ip) == sizeof(USHORT)* 8, "sizeof(ip)\n");
2061 
2062     for (i = 0; i < ipv6_testcount; i++)
2063     {
2064         init_ip6(&ip, NULL);
2065         terminator = (void *)0xdeadbeef;
2066         res = pRtlIpv6StringToAddressA(ipv6_tests[i].address, &terminator, &ip);
2067         compare_RtlIpv6StringToAddressW(ipv6_tests[i].address, (terminator != (void *)0xdeadbeef) ?
2068                                         (terminator - ipv6_tests[i].address) : -1, &ip, res);
2069 
2070         if (ipv6_tests[i].flags & win_broken_6)
2071         {
2072             ok(res == ipv6_tests[i].res || broken(res == STATUS_INVALID_PARAMETER),
2073                "[%s] res = 0x%08x, expected 0x%08x\n",
2074                ipv6_tests[i].address, res, ipv6_tests[i].res);
2075 
2076             if (res == STATUS_INVALID_PARAMETER)
2077                 continue;
2078         }
2079         else
2080         {
2081             ok(res == ipv6_tests[i].res,
2082                "[%s] res = 0x%08x, expected 0x%08x\n",
2083                ipv6_tests[i].address, res, ipv6_tests[i].res);
2084         }
2085 
2086         if (ipv6_tests[i].terminator_offset < 0)
2087         {
2088             ok(terminator == (void *)0xdeadbeef,
2089                "[%s] terminator = %p, expected it not to change\n",
2090                ipv6_tests[i].address, terminator);
2091         }
2092         else if (ipv6_tests[i].flags & win_broken_6)
2093         {
2094             PCSTR expected = ipv6_tests[i].address + ipv6_tests[i].terminator_offset;
2095             ok(terminator == expected || broken(terminator == expected + 2),
2096                "[%s] terminator = %p, expected %p\n",
2097                ipv6_tests[i].address, terminator, expected);
2098         }
2099         else
2100         {
2101             ok(terminator == ipv6_tests[i].address + ipv6_tests[i].terminator_offset,
2102                "[%s] terminator = %p, expected %p\n",
2103                ipv6_tests[i].address, terminator, ipv6_tests[i].address + ipv6_tests[i].terminator_offset);
2104         }
2105 
2106         init_ip6(&expected_ip, ipv6_tests[i].ip);
2107         ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2108            "[%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2109            ipv6_tests[i].address,
2110            ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2111            ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2112            expected_ip.s6_words[0], expected_ip.s6_words[1], expected_ip.s6_words[2], expected_ip.s6_words[3],
2113            expected_ip.s6_words[4], expected_ip.s6_words[5], expected_ip.s6_words[6], expected_ip.s6_words[7]);
2114     }
2115 }
2116 
2117 static void compare_RtlIpv6StringToAddressExW(PCSTR name_a, const struct in6_addr *addr_a, HRESULT res_a, ULONG scope_a, USHORT port_a)
2118 {
2119     WCHAR name[512];
2120     NTSTATUS res;
2121     IN6_ADDR ip;
2122     ULONG scope = 0xbadf00d;
2123     USHORT port = 0xbeef;
2124 
2125     if (!pRtlIpv6StringToAddressExW)
2126         return;
2127 
2128     pRtlMultiByteToUnicodeN(name, sizeof(name), NULL, name_a, strlen(name_a) + 1);
2129 
2130     init_ip6(&ip, NULL);
2131     res = pRtlIpv6StringToAddressExW(name, &ip, &scope, &port);
2132 
2133     ok(res == res_a, "[W:%s] res = 0x%08x, expected 0x%08x\n", name_a, res, res_a);
2134     ok(scope == scope_a, "[W:%s] scope = 0x%08x, expected 0x%08x\n", name_a, scope, scope_a);
2135     ok(port == port_a, "[W:%s] port = 0x%08x, expected 0x%08x\n", name_a, port, port_a);
2136 
2137     ok(!memcmp(&ip, addr_a, sizeof(ip)),
2138        "[W:%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2139        name_a,
2140        ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2141        ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2142        addr_a->s6_words[0], addr_a->s6_words[1], addr_a->s6_words[2], addr_a->s6_words[3],
2143        addr_a->s6_words[4], addr_a->s6_words[5], addr_a->s6_words[6], addr_a->s6_words[7]);
2144 }
2145 
2146 static void test_RtlIpv6StringToAddressEx(void)
2147 {
2148     NTSTATUS res;
2149     IN6_ADDR ip, expected_ip;
2150     ULONG scope;
2151     USHORT port;
2152     static const struct
2153     {
2154         PCSTR address;
2155         NTSTATUS res;
2156         ULONG scope;
2157         USHORT port;
2158         int ip[8];
2159     } ipv6_ex_tests[] =
2160     {
2161         { "[::]",                                           STATUS_SUCCESS,             0,          0,
2162             { 0, 0, 0, 0, 0, 0, 0, 0 } },
2163         { "[::1]:8080",                                     STATUS_SUCCESS,             0,          0x901f,
2164             { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2165         { "[::1]:0x80",                                     STATUS_SUCCESS,             0,          0x8000,
2166             { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2167         { "[::1]:0X80",                                     STATUS_SUCCESS,             0,          0x8000,
2168             { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2169         { "[::1]:080",                                      STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2170             { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2171         { "[::1]:800000000080",                             STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2172             { 0, 0, 0, 0, 0, 0, 0, 0x100 } },
2173         { "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80",   STATUS_SUCCESS,             0,          0x5000,
2174             { 0xdcfe, 0x98ba, 0x5476, 0x1032, 0xdcfe, 0x98ba, 0x5476, 0x1032 } },
2175         { "[1080:0:0:0:8:800:200C:417A]:1234",              STATUS_SUCCESS,             0,          0xd204,
2176             { 0x8010, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2177         { "[3ffe:2a00:100:7031::1]:8080",                   STATUS_SUCCESS,             0,          0x901f,
2178             { 0xfe3f, 0x2a, 1, 0x3170, 0, 0, 0, 0x100 } },
2179         { "[ 3ffe:2a00:100:7031::1]:8080",                  STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2180             { -1 } },
2181         { "[3ffe:2a00:100:7031::1 ]:8080",                  STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2182             { 0xfe3f, 0x2a, 1, 0x3170, 0, 0, 0, 0x100 } },
2183         { "[3ffe:2a00:100:7031::1].8080",                   STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2184             { 0xfe3f, 0x2a, 1, 0x3170, 0, 0, 0, 0x100 } },
2185         { "[1080::8:800:200C:417A]:8080",                   STATUS_SUCCESS,             0,          0x901f,
2186             { 0x8010, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2187         { "[1080::8:800:200C:417A]!8080",                   STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2188             { 0x8010, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2189         { "[::FFFF:129.144.52.38]:80",                      STATUS_SUCCESS,             0,          0x5000,
2190             { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2191         { "[::FFFF:129.144.52.38]:-80",                     STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2192             { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2193         { "[::FFFF:129.144.52.38]:999999999999",            STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2194             { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2195         { "[::FFFF:129.144.52.38%-8]:80",                   STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2196             { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2197         { "[::FFFF:129.144.52.38]:80",                      STATUS_SUCCESS,             0,          0x5000,
2198             { 0, 0, 0, 0, 0, 0xffff, 0x9081, 0x2634 } },
2199         { "[12345::6:7:8]:80",                              STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2200             { -1 } },
2201         { "[ff01::8:800:200C:417A%16]:8080",                STATUS_SUCCESS,             16,         0x901f,
2202             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2203         { "[ff01::8:800:200C:417A%100]:8080",               STATUS_SUCCESS,             100,        0x901f,
2204             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2205         { "[ff01::8:800:200C:417A%1000]:8080",              STATUS_SUCCESS,             1000,       0x901f,
2206             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2207         { "[ff01::8:800:200C:417A%10000]:8080",             STATUS_SUCCESS,             10000,      0x901f,
2208             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2209         { "[ff01::8:800:200C:417A%1000000]:8080",           STATUS_SUCCESS,             1000000,    0x901f,
2210             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2211         { "[ff01::8:800:200C:417A%4294967295]:8080",        STATUS_SUCCESS,             0xffffffff, 0x901f,
2212             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2213         { "[ff01::8:800:200C:417A%4294967296]:8080",        STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2214             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2215         { "[ff01::8:800:200C:417A%-1]:8080",                STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2216             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2217         { "[ff01::8:800:200C:417A%0]:8080",                 STATUS_SUCCESS,             0,          0x901f,
2218             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2219         { "[ff01::8:800:200C:417A%1",                       STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2220             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2221         { "[ff01::8:800:200C:417A%0x1000]:8080",            STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2222             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2223         { "[ff01::8:800:200C:417A/16]:8080",                STATUS_INVALID_PARAMETER,   0xbadf00d,  0xbeef,
2224             { 0x1ff, 0, 0, 0, 0x800, 8, 0xc20, 0x7a41 } },
2225     };
2226     const unsigned int ipv6_ex_testcount = sizeof(ipv6_ex_tests) / sizeof(ipv6_ex_tests[0]);
2227     const char *simple_ip = "::";
2228     unsigned int i;
2229 
2230     if (!pRtlIpv6StringToAddressExW)
2231     {
2232         skip("RtlIpv6StringToAddressExW not available\n");
2233         /* we can continue, just not test W */
2234     }
2235 
2236     if (!pRtlIpv6StringToAddressExA)
2237     {
2238         skip("RtlIpv6StringToAddressExA not available\n");
2239         return;
2240     }
2241 
2242     res = pRtlIpv6StringToAddressExA(simple_ip, &ip, &scope, &port);
2243     ok(res == STATUS_SUCCESS, "[validate] res = 0x%08x, expected STATUS_SUCCESS\n", res);
2244 
2245     init_ip6(&ip, NULL);
2246     init_ip6(&expected_ip, NULL);
2247     scope = 0xbadf00d;
2248     port = 0xbeef;
2249     res = pRtlIpv6StringToAddressExA(NULL, &ip, &scope, &port);
2250     ok(res == STATUS_INVALID_PARAMETER,
2251        "[null string] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2252     ok(scope == 0xbadf00d, "[null string] scope = 0x%08x, expected 0xbadf00d\n", scope);
2253     ok(port == 0xbeef, "[null string] port = 0x%08x, expected 0xbeef\n", port);
2254     ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2255        "[null string] ip is changed, expected it not to change\n");
2256 
2257 
2258     init_ip6(&ip, NULL);
2259     scope = 0xbadf00d;
2260     port = 0xbeef;
2261     res = pRtlIpv6StringToAddressExA(simple_ip, NULL, &scope, &port);
2262     ok(res == STATUS_INVALID_PARAMETER,
2263        "[null result] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2264     ok(scope == 0xbadf00d, "[null result] scope = 0x%08x, expected 0xbadf00d\n", scope);
2265     ok(port == 0xbeef, "[null result] port = 0x%08x, expected 0xbeef\n", port);
2266     ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2267        "[null result] ip is changed, expected it not to change\n");
2268 
2269     init_ip6(&ip, NULL);
2270     scope = 0xbadf00d;
2271     port = 0xbeef;
2272     res = pRtlIpv6StringToAddressExA(simple_ip, &ip, NULL, &port);
2273     ok(res == STATUS_INVALID_PARAMETER,
2274        "[null scope] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2275     ok(scope == 0xbadf00d, "[null scope] scope = 0x%08x, expected 0xbadf00d\n", scope);
2276     ok(port == 0xbeef, "[null scope] port = 0x%08x, expected 0xbeef\n", port);
2277     ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2278        "[null scope] ip is changed, expected it not to change\n");
2279 
2280     init_ip6(&ip, NULL);
2281     scope = 0xbadf00d;
2282     port = 0xbeef;
2283     res = pRtlIpv6StringToAddressExA(simple_ip, &ip, &scope, NULL);
2284     ok(res == STATUS_INVALID_PARAMETER,
2285        "[null port] res = 0x%08x, expected STATUS_INVALID_PARAMETER\n", res);
2286     ok(scope == 0xbadf00d, "[null port] scope = 0x%08x, expected 0xbadf00d\n", scope);
2287     ok(port == 0xbeef, "[null port] port = 0x%08x, expected 0xbeef\n", port);
2288     ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2289        "[null port] ip is changed, expected it not to change\n");
2290 
2291     /* sanity check */
2292     ok(sizeof(ip) == sizeof(USHORT)* 8, "sizeof(ip)\n");
2293 
2294     /* first we run all ip related tests, to make sure someone didnt accidentally reimplement instead of re-use. */
2295     for (i = 0; i < ipv6_testcount; i++)
2296     {
2297         ULONG scope = 0xbadf00d;
2298         USHORT port = 0xbeef;
2299         NTSTATUS expect_ret = (ipv6_tests[i].flags & ex_fail_6) ? STATUS_INVALID_PARAMETER : ipv6_tests[i].res;
2300 
2301         if (ipv6_tests[i].flags & ex_skip_6)
2302             continue;
2303 
2304         init_ip6(&ip, NULL);
2305         res = pRtlIpv6StringToAddressExA(ipv6_tests[i].address, &ip, &scope, &port);
2306         compare_RtlIpv6StringToAddressExW(ipv6_tests[i].address, &ip, res, scope, port);
2307 
2308         /* make sure nothing was changed if this function fails. */
2309         if (res == STATUS_INVALID_PARAMETER)
2310         {
2311             ok(scope == 0xbadf00d, "[%s] scope = 0x%08x, expected 0xbadf00d\n",
2312                ipv6_tests[i].address, scope);
2313             ok(port == 0xbeef, "[%s] port = 0x%08x, expected 0xbeef\n",
2314                ipv6_tests[i].address, port);
2315         }
2316         else
2317         {
2318             ok(scope != 0xbadf00d, "[%s] scope = 0x%08x, not expected 0xbadf00d\n",
2319                ipv6_tests[i].address, scope);
2320             ok(port != 0xbeef, "[%s] port = 0x%08x, not expected 0xbeef\n",
2321                ipv6_tests[i].address, port);
2322         }
2323 
2324         if (ipv6_tests[i].flags & win_broken_6)
2325         {
2326             ok(res == expect_ret || broken(res == STATUS_INVALID_PARAMETER),
2327                "[%s] res = 0x%08x, expected 0x%08x\n", ipv6_tests[i].address, res, expect_ret);
2328 
2329             if (res == STATUS_INVALID_PARAMETER)
2330                 continue;
2331         }
2332         else
2333         {
2334             ok(res == expect_ret, "[%s] res = 0x%08x, expected 0x%08x\n",
2335                ipv6_tests[i].address, res, expect_ret);
2336         }
2337 
2338         /* If ex fails but non-ex does not we cannot check if the part that is converted
2339            before it failed was correct, since there is no data for it in the table. */
2340         if (res == expect_ret)
2341         {
2342             init_ip6(&expected_ip, ipv6_tests[i].ip);
2343             ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2344                "[%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2345                ipv6_tests[i].address,
2346                ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2347                ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2348                expected_ip.s6_words[0], expected_ip.s6_words[1], expected_ip.s6_words[2], expected_ip.s6_words[3],
2349                expected_ip.s6_words[4], expected_ip.s6_words[5], expected_ip.s6_words[6], expected_ip.s6_words[7]);
2350         }
2351     }
2352 
2353     /* now we run scope / port related tests */
2354     for (i = 0; i < ipv6_ex_testcount; i++)
2355     {
2356         scope = 0xbadf00d;
2357         port = 0xbeef;
2358         init_ip6(&ip, NULL);
2359         res = pRtlIpv6StringToAddressExA(ipv6_ex_tests[i].address, &ip, &scope, &port);
2360         compare_RtlIpv6StringToAddressExW(ipv6_ex_tests[i].address, &ip, res, scope, port);
2361 
2362         ok(res == ipv6_ex_tests[i].res, "[%s] res = 0x%08x, expected 0x%08x\n",
2363            ipv6_ex_tests[i].address, res, ipv6_ex_tests[i].res);
2364         ok(scope == ipv6_ex_tests[i].scope, "[%s] scope = 0x%08x, expected 0x%08x\n",
2365            ipv6_ex_tests[i].address, scope, ipv6_ex_tests[i].scope);
2366         ok(port == ipv6_ex_tests[i].port, "[%s] port = 0x%08x, expected 0x%08x\n",
2367            ipv6_ex_tests[i].address, port, ipv6_ex_tests[i].port);
2368 
2369         init_ip6(&expected_ip, ipv6_ex_tests[i].ip);
2370         ok(!memcmp(&ip, &expected_ip, sizeof(ip)),
2371            "[%s] ip = %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n",
2372            ipv6_ex_tests[i].address,
2373            ip.s6_words[0], ip.s6_words[1], ip.s6_words[2], ip.s6_words[3],
2374            ip.s6_words[4], ip.s6_words[5], ip.s6_words[6], ip.s6_words[7],
2375            expected_ip.s6_words[0], expected_ip.s6_words[1], expected_ip.s6_words[2], expected_ip.s6_words[3],
2376            expected_ip.s6_words[4], expected_ip.s6_words[5], expected_ip.s6_words[6], expected_ip.s6_words[7]);
2377     }
2378 }
2379 
2380 static void test_LdrAddRefDll(void)
2381 {
2382     HMODULE mod, mod2;
2383     NTSTATUS status;
2384     BOOL ret;
2385 
2386     if (!pLdrAddRefDll)
2387     {
2388         win_skip( "LdrAddRefDll not supported\n" );
2389         return;
2390     }
2391 
2392     mod = LoadLibraryA("comctl32.dll");
2393     ok(mod != NULL, "got %p\n", mod);
2394     ret = FreeLibrary(mod);
2395     ok(ret, "got %d\n", ret);
2396 
2397     mod2 = GetModuleHandleA("comctl32.dll");
2398     ok(mod2 == NULL, "got %p\n", mod2);
2399 
2400     /* load, addref and release 2 times */
2401     mod = LoadLibraryA("comctl32.dll");
2402     ok(mod != NULL, "got %p\n", mod);
2403     status = pLdrAddRefDll(0, mod);
2404     ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
2405     ret = FreeLibrary(mod);
2406     ok(ret, "got %d\n", ret);
2407 
2408     mod2 = GetModuleHandleA("comctl32.dll");
2409     ok(mod2 != NULL, "got %p\n", mod2);
2410     ret = FreeLibrary(mod);
2411     ok(ret, "got %d\n", ret);
2412 
2413     mod2 = GetModuleHandleA("comctl32.dll");
2414     ok(mod2 == NULL, "got %p\n", mod2);
2415 
2416     /* pin refcount */
2417     mod = LoadLibraryA("comctl32.dll");
2418     ok(mod != NULL, "got %p\n", mod);
2419     status = pLdrAddRefDll(LDR_ADDREF_DLL_PIN, mod);
2420     ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
2421 
2422     ret = FreeLibrary(mod);
2423     ok(ret, "got %d\n", ret);
2424     ret = FreeLibrary(mod);
2425     ok(ret, "got %d\n", ret);
2426     ret = FreeLibrary(mod);
2427     ok(ret, "got %d\n", ret);
2428     ret = FreeLibrary(mod);
2429     ok(ret, "got %d\n", ret);
2430 
2431     mod2 = GetModuleHandleA("comctl32.dll");
2432     ok(mod2 != NULL, "got %p\n", mod2);
2433 }
2434 
2435 static void test_LdrLockLoaderLock(void)
2436 {
2437     ULONG_PTR magic;
2438     ULONG result;
2439     NTSTATUS status;
2440 
2441     if (!pLdrLockLoaderLock)
2442     {
2443         win_skip("LdrLockLoaderLock() is not available\n");
2444         return;
2445     }
2446 
2447     /* invalid flags */
2448     result = 10;
2449     magic = 0xdeadbeef;
2450     status = pLdrLockLoaderLock(0x10, &result, &magic);
2451     ok(status == STATUS_INVALID_PARAMETER_1, "got 0x%08x\n", status);
2452     ok(result == 0, "got %d\n", result);
2453     ok(magic == 0, "got %lx\n", magic);
2454 
2455     magic = 0xdeadbeef;
2456     status = pLdrLockLoaderLock(0x10, NULL, &magic);
2457     ok(status == STATUS_INVALID_PARAMETER_1, "got 0x%08x\n", status);
2458     ok(magic == 0, "got %lx\n", magic);
2459 
2460     result = 10;
2461     status = pLdrLockLoaderLock(0x10, &result, NULL);
2462     ok(status == STATUS_INVALID_PARAMETER_1, "got 0x%08x\n", status);
2463     ok(result == 0, "got %d\n", result);
2464 
2465     /* non-blocking mode, result is null */
2466     magic = 0xdeadbeef;
2467     status = pLdrLockLoaderLock(0x2, NULL, &magic);
2468     ok(status == STATUS_INVALID_PARAMETER_2, "got 0x%08x\n", status);
2469     ok(magic == 0, "got %lx\n", magic);
2470 
2471     /* magic pointer is null */
2472     result = 10;
2473     status = pLdrLockLoaderLock(0, &result, NULL);
2474     ok(status == STATUS_INVALID_PARAMETER_3, "got 0x%08x\n", status);
2475     ok(result == 0, "got %d\n", result);
2476 
2477     /* lock in non-blocking mode */
2478     result = 0;
2479     magic = 0;
2480     status = pLdrLockLoaderLock(0x2, &result, &magic);
2481     ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
2482     ok(result == 1, "got %d\n", result);
2483     ok(magic != 0, "got %lx\n", magic);
2484     pLdrUnlockLoaderLock(0, magic);
2485 }
2486 
2487 static void test_RtlCompressBuffer(void)
2488 {
2489     ULONG compress_workspace, decompress_workspace;
2490     static const UCHAR test_buffer[] = "WineWineWine";
2491     static UCHAR buf1[0x1000], buf2[0x1000];
2492     ULONG final_size, buf_size;
2493     UCHAR *workspace = NULL;
2494     NTSTATUS status;
2495 
2496     if (!pRtlCompressBuffer || !pRtlDecompressBuffer || !pRtlGetCompressionWorkSpaceSize)
2497     {
2498         win_skip("skipping RtlCompressBuffer tests, required functions not available\n");
2499         return;
2500     }
2501 
2502     compress_workspace = decompress_workspace = 0xdeadbeef;
2503     status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1, &compress_workspace,
2504                                              &decompress_workspace);
2505     ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
2506     ok(compress_workspace != 0, "got wrong compress_workspace %u\n", compress_workspace);
2507     workspace = HeapAlloc(GetProcessHeap(), 0, compress_workspace);
2508     ok(workspace != NULL, "HeapAlloc failed %d\n", GetLastError());
2509 
2510     /* test compression format / engine */
2511     final_size = 0xdeadbeef;
2512     status = pRtlCompressBuffer(COMPRESSION_FORMAT_NONE, test_buffer, sizeof(test_buffer),
2513                                 buf1, sizeof(buf1) - 1, 4096, &final_size, workspace);
2514     ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2515     ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size);
2516 
2517     final_size = 0xdeadbeef;
2518     status = pRtlCompressBuffer(COMPRESSION_FORMAT_DEFAULT, test_buffer, sizeof(test_buffer),
2519                                 buf1, sizeof(buf1) - 1, 4096, &final_size, workspace);
2520     ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2521     ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size);
2522 
2523     final_size = 0xdeadbeef;
2524     status = pRtlCompressBuffer(0xFF, test_buffer, sizeof(test_buffer),
2525                                 buf1, sizeof(buf1) - 1, 4096, &final_size, workspace);
2526     ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
2527     ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size);
2528 
2529     /* test compression */
2530     final_size = 0xdeadbeef;
2531     memset(buf1, 0x11, sizeof(buf1));
2532     status = pRtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, test_buffer, sizeof(test_buffer),
2533                                 buf1, sizeof(buf1), 4096, &final_size, workspace);
2534     ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
2535     ok((*(WORD *)buf1 & 0x7000) == 0x3000, "no chunk signature found %04x\n", *(WORD *)buf1);
2536     todo_wine
2537     ok(final_size < sizeof(test_buffer), "got wrong final_size %u\n", final_size);
2538 
2539     /* test decompression */
2540     buf_size = final_size;
2541     final_size = 0xdeadbeef;
2542     memset(buf2, 0x11, sizeof(buf2));
2543     status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf2, sizeof(buf2),
2544                                   buf1, buf_size, &final_size);
2545     ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
2546     ok(final_size == sizeof(test_buffer), "got wrong final_size %u\n", final_size);
2547     ok(!memcmp(buf2, test_buffer, sizeof(test_buffer)), "got wrong decoded data\n");
2548     ok(buf2[sizeof(test_buffer)] == 0x11, "too many bytes written\n");
2549 
2550     /* buffer too small */
2551     final_size = 0xdeadbeef;
2552     memset(buf1, 0x11, sizeof(buf1));
2553     status = pRtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, test_buffer, sizeof(test_buffer),
2554                                 buf1, 4, 4096, &final_size, workspace);
2555     ok(status == STATUS_BUFFER_TOO_SMALL, "got wrong status 0x%08x\n", status);
2556 
2557     HeapFree(GetProcessHeap(), 0, workspace);
2558 }
2559 
2560 static void test_RtlGetCompressionWorkSpaceSize(void)
2561 {
2562     ULONG compress_workspace, decompress_workspace;
2563     NTSTATUS status;
2564 
2565     if (!pRtlGetCompressionWorkSpaceSize)
2566     {
2567         win_skip("RtlGetCompressionWorkSpaceSize is not available\n");
2568         return;
2569     }
2570 
2571     /* test invalid format / engine */
2572     status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_NONE, &compress_workspace,
2573                                              &decompress_workspace);
2574     ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2575 
2576     status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_DEFAULT, &compress_workspace,
2577                                              &decompress_workspace);
2578     ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2579 
2580     status = pRtlGetCompressionWorkSpaceSize(0xFF, &compress_workspace, &decompress_workspace);
2581     ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
2582 
2583     /* test LZNT1 with normal and maximum compression */
2584     compress_workspace = decompress_workspace = 0xdeadbeef;
2585     status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1, &compress_workspace,
2586                                              &decompress_workspace);
2587     ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
2588     ok(compress_workspace != 0, "got wrong compress_workspace %u\n", compress_workspace);
2589     ok(decompress_workspace == 0x1000, "got wrong decompress_workspace %u\n", decompress_workspace);
2590 
2591     compress_workspace = decompress_workspace = 0xdeadbeef;
2592     status = pRtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM,
2593                                              &compress_workspace, &decompress_workspace);
2594     ok(status == STATUS_SUCCESS, "got wrong status 0x%08x\n", status);
2595     ok(compress_workspace != 0, "got wrong compress_workspace %u\n", compress_workspace);
2596     ok(decompress_workspace == 0x1000, "got wrong decompress_workspace %u\n", decompress_workspace);
2597 }
2598 
2599 /* helper for test_RtlDecompressBuffer, checks if a chunk is incomplete */
2600 static BOOL is_incomplete_chunk(const UCHAR *compressed, ULONG compressed_size, BOOL check_all)
2601 {
2602     ULONG chunk_size;
2603 
2604     if (compressed_size <= sizeof(WORD))
2605         return TRUE;
2606 
2607     while (compressed_size >= sizeof(WORD))
2608     {
2609         chunk_size = (*(WORD *)compressed & 0xFFF) + 1;
2610         if (compressed_size < sizeof(WORD) + chunk_size)
2611             return TRUE;
2612         if (!check_all)
2613             break;
2614         compressed      += sizeof(WORD) + chunk_size;
2615         compressed_size -= sizeof(WORD) + chunk_size;
2616     }
2617 
2618     return FALSE;
2619 }
2620 
2621 #define DECOMPRESS_BROKEN_FRAGMENT     1 /* < Win 7 */
2622 #define DECOMPRESS_BROKEN_TRUNCATED    2 /* broken on all machines */
2623 
2624 static void test_RtlDecompressBuffer(void)
2625 {
2626     static const struct
2627     {
2628         UCHAR compressed[32];
2629         ULONG compressed_size;
2630         NTSTATUS status;
2631         UCHAR uncompressed[32];
2632         ULONG uncompressed_size;
2633         DWORD broken_flags;
2634     }
2635     test_lznt[] =
2636     {
2637         /* 4 byte uncompressed chunk */
2638         {
2639             {0x03, 0x30, 'W', 'i', 'n', 'e'},
2640             6,
2641             STATUS_SUCCESS,
2642             "Wine",
2643             4,
2644             DECOMPRESS_BROKEN_FRAGMENT
2645         },
2646         /* 8 byte uncompressed chunk */
2647         {
2648             {0x07, 0x30, 'W', 'i', 'n', 'e', 'W', 'i', 'n', 'e'},
2649             10,
2650             STATUS_SUCCESS,
2651             "WineWine",
2652             8,
2653             DECOMPRESS_BROKEN_FRAGMENT
2654         },
2655         /* 4 byte compressed chunk */
2656         {
2657             {0x04, 0xB0, 0x00, 'W', 'i', 'n', 'e'},
2658             7,
2659             STATUS_SUCCESS,
2660             "Wine",
2661             4
2662         },
2663         /* 8 byte compressed chunk */
2664         {
2665             {0x08, 0xB0, 0x00, 'W', 'i', 'n', 'e', 'W', 'i', 'n', 'e'},
2666             11,
2667             STATUS_SUCCESS,
2668             "WineWine",
2669             8
2670         },
2671         /* compressed chunk using backwards reference */
2672         {
2673             {0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x01, 0x30},
2674             9,
2675             STATUS_SUCCESS,
2676             "WineWine",
2677             8,
2678             DECOMPRESS_BROKEN_TRUNCATED
2679         },
2680         /* compressed chunk using backwards reference with length > bytes_read */
2681         {
2682             {0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05, 0x30},
2683             9,
2684             STATUS_SUCCESS,
2685             "WineWineWine",
2686             12,
2687             DECOMPRESS_BROKEN_TRUNCATED
2688         },
2689         /* same as above, but unused bits != 0 */
2690         {
2691             {0x06, 0xB0, 0x30, 'W', 'i', 'n', 'e', 0x01, 0x30},
2692             9,
2693             STATUS_SUCCESS,
2694             "WineWine",
2695             8,
2696             DECOMPRESS_BROKEN_TRUNCATED
2697         },
2698         /* compressed chunk without backwards reference and unused bits != 0 */
2699         {
2700             {0x01, 0xB0, 0x02, 'W'},
2701             4,
2702             STATUS_SUCCESS,
2703             "W",
2704             1
2705         },
2706         /* termination sequence after first chunk */
2707         {
2708             {0x03, 0x30, 'W', 'i', 'n', 'e', 0x00, 0x00, 0x03, 0x30, 'W', 'i', 'n', 'e'},
2709             14,
2710             STATUS_SUCCESS,
2711             "Wine",
2712             4,
2713             DECOMPRESS_BROKEN_FRAGMENT
2714         },
2715         /* compressed chunk using backwards reference with 4 bit offset, 12 bit length */
2716         {
2717             {0x14, 0xB0, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
2718                          0x00, 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
2719                          0x01, 0x01, 0xF0},
2720             23,
2721             STATUS_SUCCESS,
2722             "ABCDEFGHIJKLMNOPABCD",
2723             20,
2724             DECOMPRESS_BROKEN_TRUNCATED
2725         },
2726         /* compressed chunk using backwards reference with 5 bit offset, 11 bit length */
2727         {
2728             {0x15, 0xB0, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
2729                          0x00, 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
2730                          0x02, 'A', 0x00, 0x78},
2731             24,
2732             STATUS_SUCCESS,
2733             "ABCDEFGHIJKLMNOPABCD",
2734             20,
2735             DECOMPRESS_BROKEN_TRUNCATED
2736         },
2737         /* uncompressed chunk with invalid magic */
2738         {
2739             {0x03, 0x20, 'W', 'i', 'n', 'e'},
2740             6,
2741             STATUS_SUCCESS,
2742             "Wine",
2743             4,
2744             DECOMPRESS_BROKEN_FRAGMENT
2745         },
2746         /* compressed chunk with invalid magic */
2747         {
2748             {0x04, 0xA0, 0x00, 'W', 'i', 'n', 'e'},
2749             7,
2750             STATUS_SUCCESS,
2751             "Wine",
2752             4
2753         },
2754         /* garbage byte after end of buffer */
2755         {
2756             {0x00, 0xB0, 0x02, 0x01},
2757             4,
2758             STATUS_SUCCESS,
2759             "",
2760             0
2761         },
2762         /* empty compressed chunk */
2763         {
2764             {0x00, 0xB0, 0x00},
2765             3,
2766             STATUS_SUCCESS,
2767             "",
2768             0
2769         },
2770         /* empty compressed chunk with unused bits != 0 */
2771         {
2772             {0x00, 0xB0, 0x01},
2773             3,
2774             STATUS_SUCCESS,
2775             "",
2776             0
2777         },
2778         /* empty input buffer */
2779         {
2780             {0},
2781             0,
2782             STATUS_BAD_COMPRESSION_BUFFER,
2783         },
2784         /* incomplete chunk header */
2785         {
2786             {0x01},
2787             1,
2788             STATUS_BAD_COMPRESSION_BUFFER
2789         },
2790         /* incomplete chunk header */
2791         {
2792             {0x00, 0x30},
2793             2,
2794             STATUS_BAD_COMPRESSION_BUFFER
2795         },
2796         /* compressed chunk with invalid backwards reference */
2797         {
2798             {0x06, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05, 0x40},
2799             9,
2800             STATUS_BAD_COMPRESSION_BUFFER
2801         },
2802         /* compressed chunk with incomplete backwards reference */
2803         {
2804             {0x05, 0xB0, 0x10, 'W', 'i', 'n', 'e', 0x05},
2805             8,
2806             STATUS_BAD_COMPRESSION_BUFFER
2807         },
2808         /* incomplete uncompressed chunk */
2809         {
2810             {0x07, 0x30, 'W', 'i', 'n', 'e'},
2811             6,
2812             STATUS_BAD_COMPRESSION_BUFFER
2813         },
2814         /* incomplete compressed chunk */
2815         {
2816             {0x08, 0xB0, 0x00, 'W', 'i', 'n', 'e'},
2817             7,
2818             STATUS_BAD_COMPRESSION_BUFFER
2819         },
2820         /* two compressed chunks, the second one incomplete */
2821         {
2822             {0x00, 0xB0, 0x02, 0x00, 0xB0},
2823             5,
2824             STATUS_BAD_COMPRESSION_BUFFER,
2825         }
2826     };
2827 
2828     static UCHAR buf[0x2000], workspace[0x1000];
2829     NTSTATUS status, expected_status;
2830     ULONG final_size;
2831     int i;
2832 
2833     if (!pRtlDecompressBuffer || !pRtlDecompressFragment)
2834     {
2835         win_skip("RtlDecompressBuffer or RtlDecompressFragment is not available\n");
2836         return;
2837     }
2838 
2839     /* test compression format / engine */
2840     final_size = 0xdeadbeef;
2841     status = pRtlDecompressBuffer(COMPRESSION_FORMAT_NONE, buf, sizeof(buf), test_lznt[0].compressed,
2842                                   test_lznt[0].compressed_size, &final_size);
2843     ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2844     ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size);
2845 
2846     final_size = 0xdeadbeef;
2847     status = pRtlDecompressBuffer(COMPRESSION_FORMAT_DEFAULT, buf, sizeof(buf), test_lznt[0].compressed,
2848                                   test_lznt[0].compressed_size, &final_size);
2849     ok(status == STATUS_INVALID_PARAMETER, "got wrong status 0x%08x\n", status);
2850     ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size);
2851 
2852     final_size = 0xdeadbeef;
2853     status = pRtlDecompressBuffer(0xFF, buf, sizeof(buf), test_lznt[0].compressed,
2854                                   test_lznt[0].compressed_size, &final_size);
2855     ok(status == STATUS_UNSUPPORTED_COMPRESSION, "got wrong status 0x%08x\n", status);
2856     ok(final_size == 0xdeadbeef, "got wrong final_size %u\n", final_size);
2857 
2858     /* regular tests for RtlDecompressBuffer */
2859     for (i = 0; i < sizeof(test_lznt) / sizeof(test_lznt[0]); i++)
2860     {
2861         trace("Running test %d (compressed_size=%u, uncompressed_size=%u, status=0x%08x)\n",
2862               i, test_lznt[i].compressed_size, test_lznt[i].uncompressed_size, test_lznt[i].status);
2863 
2864         /* test with very big buffer */
2865         final_size = 0xdeadbeef;
2866         memset(buf, 0x11, sizeof(buf));
2867         status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
2868                                       test_lznt[i].compressed_size, &final_size);
2869         ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
2870            (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status);
2871         if (!status)
2872         {
2873             ok(final_size == test_lznt[i].uncompressed_size,
2874                "%d: got wrong final_size %u\n", i, final_size);
2875             ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
2876                "%d: got wrong decoded data\n", i);
2877             ok(buf[test_lznt[i].uncompressed_size] == 0x11,
2878                "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size);
2879         }
2880 
2881         /* test that modifier for compression engine is ignored */
2882         final_size = 0xdeadbeef;
2883         memset(buf, 0x11, sizeof(buf));
2884         status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_MAXIMUM, buf, sizeof(buf),
2885                                       test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
2886         ok(status == test_lznt[i].status || broken(status == STATUS_BAD_COMPRESSION_BUFFER &&
2887            (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)), "%d: got wrong status 0x%08x\n", i, status);
2888         if (!status)
2889         {
2890             ok(final_size == test_lznt[i].uncompressed_size,
2891                "%d: got wrong final_size %u\n", i, final_size);
2892             ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
2893                "%d: got wrong decoded data\n", i);
2894             ok(buf[test_lznt[i].uncompressed_size] == 0x11,
2895                "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size);
2896         }
2897 
2898         /* test with expected output size */
2899         if (test_lznt[i].uncompressed_size > 0)
2900         {
2901             final_size = 0xdeadbeef;
2902             memset(buf, 0x11, sizeof(buf));
2903             status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, test_lznt[i].uncompressed_size,
2904                                           test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
2905             ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
2906             if (!status)
2907             {
2908                 ok(final_size == test_lznt[i].uncompressed_size,
2909                    "%d: got wrong final_size %u\n", i, final_size);
2910                 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
2911                    "%d: got wrong decoded data\n", i);
2912                 ok(buf[test_lznt[i].uncompressed_size] == 0x11,
2913                    "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size);
2914             }
2915         }
2916 
2917         /* test with smaller output size */
2918         if (test_lznt[i].uncompressed_size > 1)
2919         {
2920             final_size = 0xdeadbeef;
2921             memset(buf, 0x11, sizeof(buf));
2922             status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, test_lznt[i].uncompressed_size - 1,
2923                                           test_lznt[i].compressed, test_lznt[i].compressed_size, &final_size);
2924             if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_TRUNCATED)
2925                 todo_wine
2926                 ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
2927             else
2928                 ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
2929             if (!status)
2930             {
2931                 ok(final_size == test_lznt[i].uncompressed_size - 1,
2932                    "%d: got wrong final_size %u\n", i, final_size);
2933                 ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size - 1),
2934                    "%d: got wrong decoded data\n", i);
2935                 ok(buf[test_lznt[i].uncompressed_size - 1] == 0x11,
2936                    "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size - 1);
2937             }
2938         }
2939 
2940         /* test with zero output size */
2941         final_size = 0xdeadbeef;
2942         memset(buf, 0x11, sizeof(buf));
2943         status = pRtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, buf, 0, test_lznt[i].compressed,
2944                                       test_lznt[i].compressed_size, &final_size);
2945         if (is_incomplete_chunk(test_lznt[i].compressed, test_lznt[i].compressed_size, FALSE))
2946             ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
2947         else
2948         {
2949             ok(status == STATUS_SUCCESS, "%d: got wrong status 0x%08x\n", i, status);
2950             ok(final_size == 0, "%d: got wrong final_size %u\n", i, final_size);
2951             ok(buf[0] == 0x11, "%d: buf[0] was modified\n", i);
2952         }
2953 
2954         /* test RtlDecompressFragment with offset = 0 */
2955         final_size = 0xdeadbeef;
2956         memset(buf, 0x11, sizeof(buf));
2957         status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
2958                                         test_lznt[i].compressed_size, 0, &final_size, workspace);
2959         if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)
2960             todo_wine
2961             ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
2962         else
2963             ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
2964         if (!status)
2965         {
2966             ok(final_size == test_lznt[i].uncompressed_size,
2967                "%d: got wrong final_size %u\n", i, final_size);
2968             ok(!memcmp(buf, test_lznt[i].uncompressed, test_lznt[i].uncompressed_size),
2969                "%d: got wrong decoded data\n", i);
2970             ok(buf[test_lznt[i].uncompressed_size] == 0x11,
2971                "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size);
2972         }
2973 
2974         /* test RtlDecompressFragment with offset = 1 */
2975         final_size = 0xdeadbeef;
2976         memset(buf, 0x11, sizeof(buf));
2977         status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
2978                                         test_lznt[i].compressed_size, 1, &final_size, workspace);
2979         if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)
2980             todo_wine
2981             ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
2982         else
2983             ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
2984         if (!status)
2985         {
2986             if (test_lznt[i].uncompressed_size == 0)
2987             {
2988                 todo_wine
2989                 ok(final_size == 4095, "%d: got wrong final_size %u\n", i, final_size);
2990                 /* Buffer doesn't contain any useful value on Windows */
2991                 ok(buf[4095] == 0x11, "%d: buf[4095] was modified\n", i);
2992             }
2993             else
2994             {
2995                 ok(final_size == test_lznt[i].uncompressed_size - 1,
2996                    "%d: got wrong final_size %u\n", i, final_size);
2997                 ok(!memcmp(buf, test_lznt[i].uncompressed + 1, test_lznt[i].uncompressed_size - 1),
2998                    "%d: got wrong decoded data\n", i);
2999                 ok(buf[test_lznt[i].uncompressed_size - 1] == 0x11,
3000                    "%d: buf[%u] was modified\n", i, test_lznt[i].uncompressed_size - 1);
3001             }
3002         }
3003 
3004         /* test RtlDecompressFragment with offset = 4095 */
3005         final_size = 0xdeadbeef;
3006         memset(buf, 0x11, sizeof(buf));
3007         status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
3008                                         test_lznt[i].compressed_size, 4095, &final_size, workspace);
3009         if (test_lznt[i].broken_flags & DECOMPRESS_BROKEN_FRAGMENT)
3010             todo_wine
3011             ok(status == STATUS_BAD_COMPRESSION_BUFFER, "%d: got wrong status 0x%08x\n", i, status);
3012         else
3013             ok(status == test_lznt[i].status, "%d: got wrong status 0x%08x\n", i, status);
3014         if (!status)
3015         {
3016             todo_wine
3017             ok(final_size == 1, "%d: got wrong final_size %u\n", i, final_size);
3018             todo_wine
3019             ok(buf[0] == 0, "%d: padding is not zero\n", i);
3020             ok(buf[1] == 0x11, "%d: buf[1] was modified\n", i);
3021         }
3022 
3023         /* test RtlDecompressFragment with offset = 4096 */
3024         final_size = 0xdeadbeef;
3025         memset(buf, 0x11, sizeof(buf));
3026         status = pRtlDecompressFragment(COMPRESSION_FORMAT_LZNT1, buf, sizeof(buf), test_lznt[i].compressed,
3027                                         test_lznt[i].compressed_size, 4096, &final_size, workspace);
3028         expected_status = is_incomplete_chunk(test_lznt[i].compressed, test_lznt[i].compressed_size, TRUE) ?
3029                           test_lznt[i].status : STATUS_SUCCESS;
3030         ok(status == expected_status, "%d: got wrong status 0x%08x, expected 0x%08x\n", i, status, expected_status);
3031         if (!status)
3032         {
3033             ok(final_size == 0, "%d: got wrong final_size %u\n", i, final_size);
3034             ok(buf[0] == 0x11, "%d: buf[4096] was modified\n", i);
3035         }
3036     }
3037 }
3038 
3039 #undef DECOMPRESS_BROKEN_FRAGMENT
3040 #undef DECOMPRESS_BROKEN_TRUNCATED
3041 
3042 struct critsect_locked_info
3043 {
3044     CRITICAL_SECTION crit;
3045     HANDLE semaphores[2];
3046 };
3047 
3048 static DWORD WINAPI critsect_locked_thread(void *param)
3049 {
3050     struct critsect_locked_info *info = param;
3051     DWORD ret;
3052 
3053     ret = pRtlIsCriticalSectionLocked(&info->crit);
3054     ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3055     ret = pRtlIsCriticalSectionLockedByThread(&info->crit);
3056     ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3057 
3058     ReleaseSemaphore(info->semaphores[0], 1, NULL);
3059     ret = WaitForSingleObject(info->semaphores[1], 1000);
3060     ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3061 
3062     ret = pRtlIsCriticalSectionLocked(&info->crit);
3063     ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3064     ret = pRtlIsCriticalSectionLockedByThread(&info->crit);
3065     ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3066 
3067     EnterCriticalSection(&info->crit);
3068 
3069     ret = pRtlIsCriticalSectionLocked(&info->crit);
3070     ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3071     ret = pRtlIsCriticalSectionLockedByThread(&info->crit);
3072     ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3073 
3074     ReleaseSemaphore(info->semaphores[0], 1, NULL);
3075     ret = WaitForSingleObject(info->semaphores[1], 1000);
3076     ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3077 
3078     LeaveCriticalSection(&info->crit);
3079     return 0;
3080 }
3081 
3082 static void test_RtlIsCriticalSectionLocked(void)
3083 {
3084     struct critsect_locked_info info;
3085     HANDLE thread;
3086     BOOL ret;
3087 
3088     if (!pRtlIsCriticalSectionLocked || !pRtlIsCriticalSectionLockedByThread)
3089     {
3090         win_skip("skipping RtlIsCriticalSectionLocked tests, required functions not available\n");
3091         return;
3092     }
3093 
3094     InitializeCriticalSection(&info.crit);
3095     info.semaphores[0] = CreateSemaphoreW(NULL, 0, 1, NULL);
3096     ok(info.semaphores[0] != NULL, "CreateSemaphore failed with %u\n", GetLastError());
3097     info.semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
3098     ok(info.semaphores[1] != NULL, "CreateSemaphore failed with %u\n", GetLastError());
3099 
3100     ret = pRtlIsCriticalSectionLocked(&info.crit);
3101     ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3102     ret = pRtlIsCriticalSectionLockedByThread(&info.crit);
3103     ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3104 
3105     EnterCriticalSection(&info.crit);
3106 
3107     ret = pRtlIsCriticalSectionLocked(&info.crit);
3108     ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3109     ret = pRtlIsCriticalSectionLockedByThread(&info.crit);
3110     ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3111 
3112     thread = CreateThread(NULL, 0, critsect_locked_thread, &info, 0, NULL);
3113     ok(thread != NULL, "CreateThread failed with %u\n", GetLastError());
3114     ret = WaitForSingleObject(info.semaphores[0], 1000);
3115     ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3116 
3117     LeaveCriticalSection(&info.crit);
3118 
3119     ReleaseSemaphore(info.semaphores[1], 1, NULL);
3120     ret = WaitForSingleObject(info.semaphores[0], 1000);
3121     ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3122 
3123     ret = pRtlIsCriticalSectionLocked(&info.crit);
3124     ok(ret == TRUE, "expected TRUE, got %u\n", ret);
3125     ret = pRtlIsCriticalSectionLockedByThread(&info.crit);
3126     ok(ret == FALSE, "expected FALSE, got %u\n", ret);
3127 
3128     ReleaseSemaphore(info.semaphores[1], 1, NULL);
3129     ret = WaitForSingleObject(thread, 1000);
3130     ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", ret);
3131 
3132     CloseHandle(thread);
3133     CloseHandle(info.semaphores[0]);
3134     CloseHandle(info.semaphores[1]);
3135     DeleteCriticalSection(&info.crit);
3136 }
3137 
3138 static void test_RtlInitializeCriticalSectionEx(void)
3139 {
3140     static const CRITICAL_SECTION_DEBUG *no_debug = (void *)~(ULONG_PTR)0;
3141     CRITICAL_SECTION cs;
3142 
3143     if (!pRtlInitializeCriticalSectionEx)
3144     {
3145         win_skip("RtlInitializeCriticalSectionEx is not available\n");
3146         return;
3147     }
3148 
3149     memset(&cs, 0x11, sizeof(cs));
3150     pRtlInitializeCriticalSectionEx(&cs, 0, 0);
3151     ok((cs.DebugInfo != NULL && cs.DebugInfo != no_debug) || broken(cs.DebugInfo == no_debug) /* >= Win 8 */,
3152        "expected DebugInfo != NULL and DebugInfo != ~0, got %p\n", cs.DebugInfo);
3153     ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3154     ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
3155     ok(cs.LockSemaphore == NULL, "expected LockSemaphore == NULL, got %p\n", cs.LockSemaphore);
3156     ok(cs.SpinCount == 0 || broken(cs.SpinCount != 0) /* >= Win 8 */,
3157        "expected SpinCount == 0, got %ld\n", cs.SpinCount);
3158     RtlDeleteCriticalSection((PRTL_CRITICAL_SECTION)&cs);
3159 
3160     memset(&cs, 0x11, sizeof(cs));
3161     pRtlInitializeCriticalSectionEx(&cs, 0, RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO);
3162     todo_wine
3163     ok(cs.DebugInfo == no_debug, "expected DebugInfo == ~0, got %p\n", cs.DebugInfo);
3164     ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3165     ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
3166     ok(cs.LockSemaphore == NULL, "expected LockSemaphore == NULL, got %p\n", cs.LockSemaphore);
3167     ok(cs.SpinCount == 0 || broken(cs.SpinCount != 0) /* >= Win 8 */,
3168        "expected SpinCount == 0, got %ld\n", cs.SpinCount);
3169     RtlDeleteCriticalSection((PRTL_CRITICAL_SECTION)&cs);
3170 }
3171 
3172 static void test_RtlLeaveCriticalSection(void)
3173 {
3174     RTL_CRITICAL_SECTION cs;
3175     NTSTATUS status;
3176 
3177     if (!pRtlInitializeCriticalSectionEx)
3178         return; /* Skip winxp */
3179 
3180     status = RtlInitializeCriticalSection(&cs);
3181     ok(!status, "RtlInitializeCriticalSection failed: %x\n", status);
3182 
3183     status = RtlEnterCriticalSection(&cs);
3184     ok(!status, "RtlEnterCriticalSection failed: %x\n", status);
3185     todo_wine
3186     ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount);
3187     ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount);
3188     ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n");
3189 
3190     status = RtlLeaveCriticalSection(&cs);
3191     ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
3192     ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3193     ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
3194     ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
3195 
3196     /*
3197      * Trying to leave a section that wasn't acquired modifies RecursionCount to an invalid value,
3198      * but doesn't modify LockCount so that an attempt to enter the section later will work.
3199      */
3200     status = RtlLeaveCriticalSection(&cs);
3201     ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
3202     ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3203     ok(cs.RecursionCount == -1, "expected RecursionCount == -1, got %d\n", cs.RecursionCount);
3204     ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
3205 
3206     /* and again */
3207     status = RtlLeaveCriticalSection(&cs);
3208     ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
3209     ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3210     ok(cs.RecursionCount == -2, "expected RecursionCount == -2, got %d\n", cs.RecursionCount);
3211     ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
3212 
3213     /* entering section fixes RecursionCount */
3214     status = RtlEnterCriticalSection(&cs);
3215     ok(!status, "RtlEnterCriticalSection failed: %x\n", status);
3216     todo_wine
3217     ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount);
3218     ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount);
3219     ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n");
3220 
3221     status = RtlLeaveCriticalSection(&cs);
3222     ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
3223     ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
3224     ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
3225     ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
3226 
3227     status = RtlDeleteCriticalSection(&cs);
3228     ok(!status, "RtlDeleteCriticalSection failed: %x\n", status);
3229 }
3230 
3231 struct ldr_enum_context
3232 {
3233     BOOL abort;
3234     BOOL found;
3235     int  count;
3236 };
3237 
3238 static void WINAPI ldr_enum_callback(LDR_MODULE *module, void *context, BOOLEAN *stop)
3239 {
3240     static const WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0};
3241     struct ldr_enum_context *ctx = context;
3242 
3243     if (!lstrcmpiW(module->BaseDllName.Buffer, ntdllW))
3244         ctx->found = TRUE;
3245 
3246     ctx->count++;
3247     *stop = ctx->abort;
3248 }
3249 
3250 static void test_LdrEnumerateLoadedModules(void)
3251 {
3252     struct ldr_enum_context ctx;
3253     NTSTATUS status;
3254 
3255     if (!pLdrEnumerateLoadedModules)
3256     {
3257         win_skip("LdrEnumerateLoadedModules not available\n");
3258         return;
3259     }
3260 
3261     ctx.abort = FALSE;
3262     ctx.found = FALSE;
3263     ctx.count = 0;
3264     status = pLdrEnumerateLoadedModules(NULL, ldr_enum_callback, &ctx);
3265     ok(status == STATUS_SUCCESS, "LdrEnumerateLoadedModules failed with %08x\n", status);
3266     ok(ctx.count > 1, "Expected more than one module, got %d\n", ctx.count);
3267     ok(ctx.found, "Could not find ntdll in list of modules\n");
3268 
3269     ctx.abort = TRUE;
3270     ctx.count = 0;
3271     status = pLdrEnumerateLoadedModules(NULL, ldr_enum_callback, &ctx);
3272     ok(status == STATUS_SUCCESS, "LdrEnumerateLoadedModules failed with %08x\n", status);
3273     ok(ctx.count == 1, "Expected exactly one module, got %d\n", ctx.count);
3274 
3275     status = pLdrEnumerateLoadedModules((void *)0x1, ldr_enum_callback, (void *)0xdeadbeef);
3276     ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
3277 
3278     status = pLdrEnumerateLoadedModules((void *)0xdeadbeef, ldr_enum_callback, (void *)0xdeadbeef);
3279     ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
3280 
3281     status = pLdrEnumerateLoadedModules(NULL, NULL, (void *)0xdeadbeef);
3282     ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
3283 }
3284 
3285 static void test_RtlQueryPackageIdentity(void)
3286 {
3287     const WCHAR programW[] = {'M','i','c','r','o','s','o','f','t','.','W','i','n','d','o','w','s','.',
3288                               'P','h','o','t','o','s','_','8','w','e','k','y','b','3','d','8','b','b','w','e','!','A','p','p',0};
3289     const WCHAR fullnameW[] = {'M','i','c','r','o','s','o','f','t','.','W','i','n','d','o','w','s','.',
3290                                'P','h','o','t','o','s', 0};
3291     const WCHAR appidW[] = {'A','p','p',0};
3292     IApplicationActivationManager *manager;
3293     WCHAR buf1[MAX_PATH], buf2[MAX_PATH];
3294     HANDLE process, token;
3295     SIZE_T size1, size2;
3296     NTSTATUS status;
3297     DWORD processid;
3298     HRESULT hr;
3299     BOOL ret;
3300 
3301     if (!pRtlQueryPackageIdentity)
3302     {
3303         win_skip("RtlQueryPackageIdentity not available\n");
3304         return;
3305     }
3306 
3307     size1 = size2 = MAX_PATH * sizeof(WCHAR);
3308     status = pRtlQueryPackageIdentity((HANDLE)~(ULONG_PTR)3, buf1, &size1, buf2, &size2, NULL);
3309     ok(status == STATUS_NOT_FOUND, "expected STATUS_NOT_FOUND, got %08x\n", status);
3310 
3311     CoInitializeEx(0, COINIT_APARTMENTTHREADED);
3312     hr = CoCreateInstance(&CLSID_ApplicationActivationManager, NULL, CLSCTX_LOCAL_SERVER,
3313                           &IID_IApplicationActivationManager, (void **)&manager);
3314     if (FAILED(hr))
3315     {
3316         todo_wine win_skip("Failed to create ApplicationActivationManager (%x)\n", hr);
3317         goto done;
3318     }
3319 
3320     hr = IApplicationActivationManager_ActivateApplication(manager, programW, NULL,
3321                                                            AO_NOERRORUI, &processid);
3322     if (FAILED(hr))
3323     {
3324         todo_wine win_skip("Failed to start program (%x)\n", hr);
3325         IApplicationActivationManager_Release(manager);
3326         goto done;
3327     }
3328 
3329     process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE, FALSE, processid);
3330     ok(process != NULL, "OpenProcess failed with %u\n", GetLastError());
3331     ret = OpenProcessToken(process, TOKEN_QUERY, &token);
3332     ok(ret, "OpenProcessToken failed with error %u\n", GetLastError());
3333 
3334     size1 = size2 = MAX_PATH * sizeof(WCHAR);
3335     status = pRtlQueryPackageIdentity(token, buf1, &size1, buf2, &size2, NULL);
3336     ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
3337 
3338     ok(!memcmp(buf1, fullnameW, sizeof(fullnameW) - sizeof(WCHAR)),
3339        "Expected buf1 to begin with %s, got %s\n", wine_dbgstr_w(fullnameW), wine_dbgstr_w(buf1));
3340     ok(size1 >= sizeof(WCHAR) && !(size1 % sizeof(WCHAR)), "Unexpected size1 = %lu\n", size1);
3341     ok(buf1[size1 / sizeof(WCHAR) - 1] == 0, "Expected buf1[%lu] == 0\n", size1 / sizeof(WCHAR) - 1);
3342 
3343     ok(!lstrcmpW(buf2, appidW), "Expected buf2 to be %s, got %s\n", wine_dbgstr_w(appidW), wine_dbgstr_w(buf2));
3344     ok(size2 >= sizeof(WCHAR) && !(size2 % sizeof(WCHAR)), "Unexpected size2 = %lu\n", size2);
3345     ok(buf2[size2 / sizeof(WCHAR) - 1] == 0, "Expected buf2[%lu] == 0\n", size2 / sizeof(WCHAR) - 1);
3346 
3347     CloseHandle(token);
3348     TerminateProcess(process, 0);
3349     CloseHandle(process);
3350 
3351 done:
3352     CoUninitialize();
3353 }
3354 
3355 static DWORD (CALLBACK *orig_entry)(HMODULE,DWORD,LPVOID);
3356 static DWORD *dll_main_data;
3357 
3358 static inline void *get_rva( HMODULE module, DWORD va )
3359 {
3360     return (void *)((char *)module + va);
3361 }
3362 
3363 static void CALLBACK ldr_notify_callback1(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3364 {
3365     const IMAGE_IMPORT_DESCRIPTOR *imports;
3366     const IMAGE_THUNK_DATA *import_list;
3367     IMAGE_THUNK_DATA *thunk_list;
3368     DWORD *calls = context;
3369     LIST_ENTRY *mark;
3370     LDR_MODULE *mod;
3371     ULONG size;
3372     int i, j;
3373 
3374     *calls <<= 4;
3375     *calls |= reason;
3376 
3377     ok(data->Loaded.Flags == 0, "Expected flags 0, got %x\n", data->Loaded.Flags);
3378     ok(!lstrcmpiW(data->Loaded.BaseDllName->Buffer, ws2_32dllW), "Expected ws2_32.dll, got %s\n",
3379        wine_dbgstr_w(data->Loaded.BaseDllName->Buffer));
3380     ok(!!data->Loaded.DllBase, "Expected non zero base address\n");
3381     ok(data->Loaded.SizeOfImage, "Expected non zero image size\n");
3382 
3383     /* expect module to be last module listed in LdrData load order list */
3384     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
3385     mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
3386     ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
3387        data->Loaded.DllBase, mod->BaseAddress);
3388     ok(!lstrcmpiW(mod->BaseDllName.Buffer, ws2_32dllW), "Expected ws2_32.dll, got %s\n",
3389        wine_dbgstr_w(mod->BaseDllName.Buffer));
3390 
3391     /* show that imports have already been resolved */
3392     imports = RtlImageDirectoryEntryToData(data->Loaded.DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
3393     ok(!!imports, "Expected dll to have imports\n");
3394 
3395     for (i = 0; imports[i].Name; i++)
3396     {
3397         thunk_list = get_rva(data->Loaded.DllBase, (DWORD)imports[i].FirstThunk);
3398         if (imports[i].OriginalFirstThunk)
3399             import_list = get_rva(data->Loaded.DllBase, (DWORD)imports[i].OriginalFirstThunk);
3400         else
3401             import_list = thunk_list;
3402 
3403         for (j = 0; import_list[j].u1.Ordinal; j++)
3404         {
3405             ok(thunk_list[j].u1.AddressOfData > data->Loaded.SizeOfImage,
3406                "Import has not been resolved: %p\n", (void*)thunk_list[j].u1.Function);
3407         }
3408     }
3409 }
3410 
3411 static void CALLBACK ldr_notify_callback2(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3412 {
3413     DWORD *calls = context;
3414     *calls <<= 4;
3415     *calls |= reason + 2;
3416 }
3417 
3418 static BOOL WINAPI fake_dll_main(HINSTANCE instance, DWORD reason, void* reserved)
3419 {
3420     if (reason == DLL_PROCESS_ATTACH)
3421     {
3422         *dll_main_data <<= 4;
3423         *dll_main_data |= 3;
3424     }
3425     else if (reason == DLL_PROCESS_DETACH)
3426     {
3427         *dll_main_data <<= 4;
3428         *dll_main_data |= 4;
3429     }
3430     return orig_entry(instance, reason, reserved);
3431 }
3432 
3433 static void CALLBACK ldr_notify_callback_dll_main(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3434 {
3435     DWORD *calls = context;
3436     LIST_ENTRY *mark;
3437     LDR_MODULE *mod;
3438 
3439     *calls <<= 4;
3440     *calls |= reason;
3441 
3442     if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
3443         return;
3444 
3445     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
3446     mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
3447     ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
3448        data->Loaded.DllBase, mod->BaseAddress);
3449     if (mod->BaseAddress != data->Loaded.DllBase)
3450        return;
3451 
3452     orig_entry = mod->EntryPoint;
3453     mod->EntryPoint = fake_dll_main;
3454     dll_main_data = calls;
3455 }
3456 
3457 static BOOL WINAPI fake_dll_main_fail(HINSTANCE instance, DWORD reason, void* reserved)
3458 {
3459     if (reason == DLL_PROCESS_ATTACH)
3460     {
3461         *dll_main_data <<= 4;
3462         *dll_main_data |= 3;
3463     }
3464     else if (reason == DLL_PROCESS_DETACH)
3465     {
3466         *dll_main_data <<= 4;
3467         *dll_main_data |= 4;
3468     }
3469     return FALSE;
3470 }
3471 
3472 static void CALLBACK ldr_notify_callback_fail(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3473 {
3474     DWORD *calls = context;
3475     LIST_ENTRY *mark;
3476     LDR_MODULE *mod;
3477 
3478     *calls <<= 4;
3479     *calls |= reason;
3480 
3481     if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
3482         return;
3483 
3484     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
3485     mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
3486     ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
3487        data->Loaded.DllBase, mod->BaseAddress);
3488     if (mod->BaseAddress != data->Loaded.DllBase)
3489        return;
3490 
3491     orig_entry = mod->EntryPoint;
3492     mod->EntryPoint = fake_dll_main_fail;
3493     dll_main_data = calls;
3494 }
3495 
3496 static void CALLBACK ldr_notify_callback_imports(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
3497 {
3498     DWORD *calls = context;
3499 
3500     if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
3501         return;
3502 
3503     if (!lstrcmpiW(data->Loaded.BaseDllName->Buffer, crypt32dllW))
3504     {
3505         *calls <<= 4;
3506         *calls |= 1;
3507     }
3508 
3509     if (!lstrcmpiW(data->Loaded.BaseDllName->Buffer, wintrustdllW))
3510     {
3511         *calls <<= 4;
3512         *calls |= 2;
3513     }
3514 }
3515 
3516 static void test_LdrRegisterDllNotification(void)
3517 {
3518     void *cookie, *cookie2;
3519     NTSTATUS status;
3520     HMODULE mod;
3521     DWORD calls;
3522 
3523     if (!pLdrRegisterDllNotification || !pLdrUnregisterDllNotification)
3524     {
3525         win_skip("Ldr(Un)RegisterDllNotification not available\n");
3526         return;
3527     }
3528 
3529     /* generic test */
3530     status = pLdrRegisterDllNotification(0, ldr_notify_callback1, &calls, &cookie);
3531     ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3532 
3533     calls = 0;
3534     mod = LoadLibraryW(ws2_32dllW);
3535     ok(!!mod, "Failed to load library: %d\n", GetLastError());
3536     ok(calls == LDR_DLL_NOTIFICATION_REASON_LOADED, "Expected LDR_DLL_NOTIFICATION_REASON_LOADED, got %x\n", calls);
3537 
3538     calls = 0;
3539     FreeLibrary(mod);
3540     ok(calls == LDR_DLL_NOTIFICATION_REASON_UNLOADED, "Expected LDR_DLL_NOTIFICATION_REASON_UNLOADED, got %x\n", calls);
3541 
3542     /* test order of callbacks */
3543     status = pLdrRegisterDllNotification(0, ldr_notify_callback2, &calls, &cookie2);
3544     ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3545 
3546     calls = 0;
3547     mod = LoadLibraryW(ws2_32dllW);
3548     ok(!!mod, "Failed to load library: %d\n", GetLastError());
3549     ok(calls == 0x13, "Expected order 0x13, got %x\n", calls);
3550 
3551     calls = 0;
3552     FreeLibrary(mod);
3553     ok(calls == 0x24, "Expected order 0x24, got %x\n", calls);
3554 
3555     pLdrUnregisterDllNotification(cookie2);
3556     pLdrUnregisterDllNotification(cookie);
3557 
3558     /* test dll main order */
3559     status = pLdrRegisterDllNotification(0, ldr_notify_callback_dll_main, &calls, &cookie);
3560     ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3561 
3562     calls = 0;
3563     mod = LoadLibraryW(ws2_32dllW);
3564     ok(!!mod, "Failed to load library: %d\n", GetLastError());
3565     ok(calls == 0x13, "Expected order 0x13, got %x\n", calls);
3566 
3567     calls = 0;
3568     FreeLibrary(mod);
3569     ok(calls == 0x42, "Expected order 0x42, got %x\n", calls);
3570 
3571     pLdrUnregisterDllNotification(cookie);
3572 
3573     /* test dll main order */
3574     status = pLdrRegisterDllNotification(0, ldr_notify_callback_fail, &calls, &cookie);
3575     ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3576 
3577     calls = 0;
3578     mod = LoadLibraryW(ws2_32dllW);
3579     ok(!mod, "Expected library to fail loading\n");
3580     ok(calls == 0x1342, "Expected order 0x1342, got %x\n", calls);
3581 
3582     pLdrUnregisterDllNotification(cookie);
3583 
3584     /* test dll with dependencies */
3585     status = pLdrRegisterDllNotification(0, ldr_notify_callback_imports, &calls, &cookie);
3586     ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
3587 
3588     calls = 0;
3589     mod = LoadLibraryW(wintrustdllW);
3590     ok(!!mod, "Failed to load library: %d\n", GetLastError());
3591     ok(calls == 0x12, "Expected order 0x12, got %x\n", calls);
3592 
3593     FreeLibrary(mod);
3594     pLdrUnregisterDllNotification(cookie);
3595 }
3596 
3597 START_TEST(rtl)
3598 {
3599     InitFunctionPtrs();
3600 
3601     test_RtlCompareMemory();
3602     test_RtlCompareMemoryUlong();
3603     test_RtlMoveMemory();
3604     test_RtlFillMemory();
3605     test_RtlFillMemoryUlong();
3606     test_RtlZeroMemory();
3607     test_RtlUlonglongByteSwap();
3608     test_RtlUniform();
3609     test_RtlRandom();
3610     test_RtlAreAllAccessesGranted();
3611     test_RtlAreAnyAccessesGranted();
3612     test_RtlComputeCrc32();
3613     test_HandleTables();
3614     test_RtlAllocateAndInitializeSid();
3615     test_RtlDeleteTimer();
3616     test_RtlThreadErrorMode();
3617     test_LdrProcessRelocationBlock();
3618     test_RtlIpv4AddressToString();
3619     test_RtlIpv4AddressToStringEx();
3620     test_RtlIpv4StringToAddress();
3621     test_RtlIpv4StringToAddressEx();
3622     test_RtlIpv6AddressToString();
3623     test_RtlIpv6AddressToStringEx();
3624     test_RtlIpv6StringToAddress();
3625     test_RtlIpv6StringToAddressEx();
3626     test_LdrAddRefDll();
3627     test_LdrLockLoaderLock();
3628     test_RtlCompressBuffer();
3629     test_RtlGetCompressionWorkSpaceSize();
3630     test_RtlDecompressBuffer();
3631     test_RtlIsCriticalSectionLocked();
3632     test_RtlInitializeCriticalSectionEx();
3633     test_RtlLeaveCriticalSection();
3634     test_LdrEnumerateLoadedModules();
3635     test_RtlQueryPackageIdentity();
3636     test_LdrRegisterDllNotification();
3637 }
3638