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