1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Test for the Rtl*MemoryStream* series of functions
5  * PROGRAMMER:      David Quintana <gigaherz@gmail.com>
6  */
7 
8 #include "precomp.h"
9 
10 #define COBJMACROS
11 #include <ole2.h>
12 #include <wtypes.h>
13 
14 ULONG finalReleaseCallCount = 0;
15 
16 VOID
17 NTAPI
18 CustomFinalReleaseMemoryStream(PRTL_MEMORY_STREAM stream)
19 {
20     finalReleaseCallCount++;
21     trace("FinalRelease CALLED.\n");
22 }
23 
24 VOID
25 NTAPI
26 CustomFinalReleaseOutOfProcessMemoryStream(PRTL_MEMORY_STREAM stream)
27 {
28     finalReleaseCallCount++;
29     trace("FinalRelease CALLED.\n");
30     RtlFinalReleaseOutOfProcessMemoryStream(stream);
31 }
32 
33 BOOL CompareStructsAndSaveForLater(PRTL_MEMORY_STREAM pold, PRTL_MEMORY_STREAM pnew, PSTR at)
34 {
35     BOOL equal = TRUE;
36 
37     // Compare
38     if (pold->Vtbl != pnew->Vtbl) {  if (equal) { trace("%s:\n", at); equal = FALSE; } trace("Vtbl changed from %p to %p\n", pold->Vtbl, pnew->Vtbl);}
39     if (pold->RefCount != pnew->RefCount) {  if (equal) { trace("%s:\n", at); equal = FALSE; } trace("RefCount changed from %ld to %ld\n", pold->RefCount, pnew->RefCount); }
40     if (pold->Unk1 != pnew->Unk1) {  if (equal) { trace("%s:\n", at); equal = FALSE; } trace("Unk1 changed from %lu to %lu\n", pold->Unk1, pnew->Unk1); }
41     if (pold->Current != pnew->Current) {  if (equal) { trace("%s:\n", at); equal = FALSE; } trace("Current changed from %p to %p\n", pold->Current, pnew->Current); }
42     if (pold->Start != pnew->Start) {  if (equal) { trace("%s:\n", at); equal = FALSE; } trace("Start changed from %p to %p\n", pold->Start, pnew->Start); }
43     if (pold->End != pnew->End) {  if (equal) { trace("%s:\n", at); equal = FALSE; } trace("End changed from %p to %p\n", pold->End, pnew->End); }
44     if (pold->FinalRelease != pnew->FinalRelease) {  if (equal) { trace("%s:\n", at); equal = FALSE; } trace("FinalRelease changed from %p to %p\n", pold->FinalRelease, pnew->FinalRelease); }
45     if (pold->ProcessHandle != pnew->ProcessHandle) {  if (equal) { trace("%s:\n", at); equal = FALSE; } trace("ProcessHandle changed from %p to %p\n", pold->ProcessHandle, pnew->ProcessHandle); }
46 
47     // Save
48     pold->Vtbl = pnew->Vtbl;
49     pold->RefCount = pnew->RefCount;
50     pold->Unk1 = pnew->Unk1;
51     pold->Current = pnew->Current;
52     pold->Start = pnew->Start;
53     pold->End = pnew->End;
54     pold->FinalRelease = pnew->FinalRelease;
55     pold->ProcessHandle = pnew->ProcessHandle;
56 
57     return equal;
58 }
59 
60 void test_InProcess()
61 {
62     LARGE_INTEGER move;
63     ULARGE_INTEGER size;
64     HRESULT res;
65     ULONG i;
66 
67     RTL_MEMORY_STREAM stream;
68     RTL_MEMORY_STREAM previous;
69 
70     IStream * istream;
71 
72     UCHAR buffer[80];
73     UCHAR buffer2[180];
74     ULONG bytesRead;
75 
76     STATSTG stat;
77 
78     finalReleaseCallCount = 0;
79 
80     for (i = 0; i < sizeof(buffer2); i++)
81     {
82         buffer2[i] = i % UCHAR_MAX;
83     }
84 
85     memset(&stream, 0x90, sizeof(stream));
86     memset(&previous, 0x00, sizeof(previous));
87 
88     StartSeh()
89         RtlInitMemoryStream(NULL);
90     EndSeh(STATUS_ACCESS_VIOLATION);
91 
92     StartSeh()
93         RtlInitMemoryStream(&stream);
94     EndSeh(STATUS_SUCCESS);
95 
96     CompareStructsAndSaveForLater(&previous, &stream, "After init");
97 
98     ok(stream.RefCount == 0, "RefCount has a wrong value: %ld (expected %d).\n", stream.RefCount, 0);
99 
100     stream.Current = buffer2;
101     stream.Start = buffer2;
102     stream.End = buffer2 + sizeof(buffer2);
103     stream.FinalRelease = CustomFinalReleaseMemoryStream;
104 
105     CompareStructsAndSaveForLater(&previous, &stream, "After assigning");
106 
107     StartSeh()
108         IStream_QueryInterface((struct IStream*)&stream, NULL, NULL);
109     EndSeh(STATUS_ACCESS_VIOLATION);
110 
111     StartSeh()
112         IStream_QueryInterface((struct IStream*)&stream, &IID_IStream, NULL);
113     EndSeh(STATUS_ACCESS_VIOLATION);
114 
115     StartSeh()
116         IStream_QueryInterface((struct IStream*)&stream, NULL, (void**)&istream);
117     EndSeh(STATUS_ACCESS_VIOLATION);
118 
119     StartSeh()
120         res = IStream_QueryInterface((struct IStream*)&stream, &IID_IStream, (void**)&istream);
121         ok(res == S_OK, "QueryInterface to IStream returned wrong hResult: 0x%08lx.\n", res);
122         ok(stream.RefCount == 2, "RefCount has a wrong value: %ld (expected %d).\n", stream.RefCount, 2);
123     EndSeh(STATUS_SUCCESS);
124 
125     CompareStructsAndSaveForLater(&previous, &stream, "After QueryInterface");
126 
127     StartSeh()
128         res = IStream_Stat(istream, NULL, 0);
129         ok(res == STG_E_INVALIDPOINTER, "Stat to IStream returned wrong hResult: 0x%08lx.\n", res);
130     EndSeh(STATUS_SUCCESS);
131 
132     StartSeh()
133         res = IStream_Stat(istream, &stat, STATFLAG_NONAME);
134         ok(res == S_OK, "Stat to IStream returned wrong hResult: 0x%08lx.\n", res);
135     EndSeh(STATUS_SUCCESS);
136 
137     ok(stream.Current == buffer2,
138        "stream.Current points to the wrong address 0x%p (expected 0x%p)\n",
139        stream.Current, buffer2);
140     ok(stream.Start == buffer2, "stream.Start was changed unexpectedly\n");
141     ok(stream.End == buffer2 + sizeof(buffer2), "stream.End was changed unexpectedly\n");
142 
143     ok(stat.cbSize.QuadPart == ((PUCHAR)stream.End - (PUCHAR)stream.Start),
144        "stat.cbSize has the wrong value %I64u (expected %d)\n",
145        stat.cbSize.QuadPart, (PUCHAR)stream.End - (PUCHAR)stream.Start);
146 
147     CompareStructsAndSaveForLater(&previous, &stream, "After Stat");
148 
149     StartSeh()
150         res = IStream_AddRef(istream);
151         ok(res == 3, "AddRef to IStream returned wrong hResult: %ld.\n", res);
152     EndSeh(STATUS_SUCCESS);
153 
154     StartSeh()
155         res = IStream_AddRef(istream);
156         ok(res == 4, "AddRef to IStream returned wrong hResult: %ld.\n", res);
157     EndSeh(STATUS_SUCCESS);
158 
159     StartSeh()
160         res = IStream_Release(istream);
161         ok(res == 3, "Release to IStream returned wrong hResult: %ld.\n", res);
162     EndSeh(STATUS_SUCCESS);
163 
164     StartSeh()
165         res = IStream_AddRef(istream);
166         ok(res == 4, "AddRef to IStream returned wrong hResult: %ld.\n", res);
167     EndSeh(STATUS_SUCCESS);
168 
169     StartSeh()
170         res = IStream_Release(istream);
171         ok(res == 3, "Release to IStream returned wrong hResult: %ld.\n", res);
172     EndSeh(STATUS_SUCCESS);
173 
174     StartSeh()
175         res = IStream_Release(istream);
176         ok(res == 2, "Release to IStream returned wrong hResult: %ld.\n", res);
177     EndSeh(STATUS_SUCCESS);
178 
179     CompareStructsAndSaveForLater(&previous, &stream, "After AddRef");
180 
181     StartSeh()
182         res = IStream_Read(istream, NULL, 0, &bytesRead);
183         ok(res == S_OK, "Read to IStream returned wrong hResult: 0x%08lx.\n", res);
184     EndSeh(STATUS_SUCCESS);
185 
186     StartSeh()
187         res = IStream_Read(istream, buffer, 40, NULL);
188         ok(res == S_OK, "Read to IStream returned wrong hResult: 0x%08lx.\n", res);
189     EndSeh(STATUS_ACCESS_VIOLATION);
190 
191     StartSeh()
192         res = IStream_Read(istream, buffer + 40, 39, &bytesRead);
193         ok(res == S_OK, "Read to IStream returned wrong hResult: 0x%08lx.\n", res);
194     EndSeh(STATUS_SUCCESS);
195 
196     if (SUCCEEDED(res))
197     {
198         bytesRead += 40;
199         for (i = 0; i < bytesRead; i++)
200         {
201             ok(buffer[i] == i, "Buffer[%lu] contains a wrong number %u (expected %lu).\n", i, buffer[i], i);
202         }
203     }
204 
205     ok(stream.Current == buffer2 + 79,
206        "stream.Current points to the wrong address 0x%p (expected 0x%p)\n",
207        stream.Current, buffer2);
208     ok(stream.Start == buffer2, "stream.Start was changed unexpectedly\n");
209     ok(stream.End == buffer2 + sizeof(buffer2), "stream.End was changed unexpectedly\n");
210 
211     CompareStructsAndSaveForLater(&previous, &stream, "After Read 1");
212 
213     size.QuadPart = 0x9090909090909090ull;
214 
215     StartSeh()
216         move.QuadPart = -1;
217         res = IStream_Seek(istream, move, STREAM_SEEK_END, &size);
218         ok(res == STG_E_INVALIDPOINTER, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
219         ok(size.QuadPart == 0x9090909090909090ull, "Seek modified the new location in an error (0x%08lx,0x%08lx).\n", size.HighPart, size.LowPart);
220     EndSeh(STATUS_SUCCESS);
221 
222     StartSeh()
223         move.QuadPart = 0;
224         res = IStream_Seek(istream, move, STREAM_SEEK_END, &size);
225         ok(res == S_OK, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
226         ok(size.QuadPart == (PUCHAR)stream.End - (PUCHAR)stream.Start, "Seek new location unexpected value: 0x%08lx.\n", size.LowPart);
227     EndSeh(STATUS_SUCCESS);
228 
229     size.QuadPart = 0x9090909090909090ull;
230 
231     StartSeh()
232         move.QuadPart = 1;
233         res = IStream_Seek(istream, move, STREAM_SEEK_END, &size);
234         ok(res == S_OK, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
235         ok(size.QuadPart == (PUCHAR)stream.End - (PUCHAR)stream.Start - 1, "Seek new location unexpected value: 0x%08lx.\n", size.LowPart);
236     EndSeh(STATUS_SUCCESS);
237 
238     size.QuadPart = 0x9090909090909090ull;
239 
240     StartSeh()
241         move.QuadPart = 2;
242         res = IStream_Seek(istream, move, STREAM_SEEK_END, &size);
243         ok(res == S_OK, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
244         ok(size.QuadPart == (PUCHAR)stream.End - (PUCHAR)stream.Start - 2, "Seek new location unexpected value: 0x%08lx.\n", size.LowPart);
245     EndSeh(STATUS_SUCCESS);
246 
247     size.QuadPart = 0x9090909090909090ull;
248 
249     StartSeh()
250         move.QuadPart = -20;
251         res = IStream_Seek(istream, move, STREAM_SEEK_SET, &size);
252         ok(res == STG_E_INVALIDPOINTER, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
253         ok(size.QuadPart == 0x9090909090909090ull, "Seek modified the new location in an error.\n");
254     EndSeh(STATUS_SUCCESS);
255 
256     StartSeh()
257         move.QuadPart = 4000;
258         res = IStream_Seek(istream, move, STREAM_SEEK_SET, &size);
259         ok(res == STG_E_INVALIDPOINTER, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
260         ok(size.QuadPart == 0x9090909090909090ull, "Seek modified the new location in an error.\n");
261     EndSeh(STATUS_SUCCESS);
262 
263     StartSeh()
264         move.QuadPart = 0x100000000ull;
265         res = IStream_Seek(istream, move, STREAM_SEEK_SET, &size);
266 #ifdef _WIN64
267         ok(res == STG_E_INVALIDPOINTER, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
268         ok(size.QuadPart == 0x9090909090909090ull, "Seek modified the new location in an error (0x%08lx,0x%08lx).\n", size.HighPart, size.LowPart);
269 #else
270         ok(res == S_OK, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
271         ok(size.QuadPart == 0, "Seek new location unexpected value: 0x%08lx.\n", size.LowPart);
272 #endif
273     EndSeh(STATUS_SUCCESS);
274 
275 #ifdef _WIN64
276     StartSeh()
277         move.QuadPart = 0;
278         res = IStream_Seek(istream, move, STREAM_SEEK_SET, &size);
279         ok(res == S_OK, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
280         ok(size.QuadPart == 0, "Seek new location unexpected value: 0x%08lx.\n", size.LowPart);
281     EndSeh(STATUS_SUCCESS);
282 #endif
283 
284     size.QuadPart = 0x9090909090909090ull;
285 
286     StartSeh()
287         move.QuadPart = -20;
288         res = IStream_Seek(istream, move, STREAM_SEEK_CUR, &size);
289         ok(res == STG_E_INVALIDPOINTER, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
290         ok(size.QuadPart == 0x9090909090909090ull, "Seek modified the new location in an error (0x%08lx,0x%08lx).\n", size.HighPart, size.LowPart);
291     EndSeh(STATUS_SUCCESS);
292 
293     StartSeh()
294         move.QuadPart = 0x100000000ull;
295         res = IStream_Seek(istream, move, STREAM_SEEK_CUR, &size);
296 #ifdef _WIN64
297         ok(res == STG_E_INVALIDPOINTER, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
298         ok(size.QuadPart == 0x9090909090909090ull, "Seek modified the new location in an error (0x%08lx,0x%08lx).\n", size.HighPart, size.LowPart);
299 #else
300         ok(res == S_OK, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
301         ok(size.QuadPart == 0, "Seek new location unexpected value: 0x%08lx.\n", size.LowPart);
302 #endif
303     EndSeh(STATUS_SUCCESS);
304 
305     StartSeh()
306         move.QuadPart = 40;
307         res = IStream_Seek(istream, move, STREAM_SEEK_SET, &size);
308         ok(res == S_OK, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
309     EndSeh(STATUS_SUCCESS);
310 
311     ok(size.QuadPart == 40,
312        "Seek returned wrong offset %I64u (expected %d)\n",
313        size.QuadPart, 40);
314 
315     ok(stream.Current == buffer2 + 40,
316        "stream.Current points to the wrong address 0x%p (expected 0x%p)\n",
317        stream.Current, buffer2);
318     ok(stream.Start == buffer2, "stream.Start was changed unexpectedly\n");
319     ok(stream.End == buffer2 + sizeof(buffer2), "stream.End was changed unexpectedly\n");
320 
321     CompareStructsAndSaveForLater(&previous, &stream, "After Seek");
322 
323     res = IStream_Read(istream, buffer, sizeof(buffer), &bytesRead);
324 
325     ok(res == S_OK, "Read to IStream returned wrong hResult: 0x%08lx.\n", res);
326 
327     if (SUCCEEDED(res))
328     {
329         for (i = 0; i < bytesRead; i++)
330         {
331             ok(buffer[i] == (i + 40), "Buffer[%lu] contains a wrong number %u (expected %lu).\n", i, buffer[i], i + 40);
332         }
333     }
334 
335     ok(stream.Current == buffer2 + 40 + sizeof(buffer),
336        "stream.Current points to the wrong address 0x%p (expected 0x%p)\n",
337        stream.Current, buffer2);
338     ok(stream.Start == buffer2, "stream.Start was changed unexpectedly\n");
339     ok(stream.End == buffer2 + sizeof(buffer2), "stream.End was changed unexpectedly\n");
340 
341     CompareStructsAndSaveForLater(&previous, &stream, "After Read 2");
342 
343     res = IStream_Release(istream);
344 
345     ok(res == 1, "Release to IStream returned wrong hResult: 0x%08lx.\n", res);
346 
347     ok(stream.RefCount == 1, "RefCount has a wrong value: %ld (expected %d).\n", stream.RefCount, 1);
348 
349     res = IStream_Release(istream);
350 
351     ok(res == S_OK, "Release to IStream returned wrong hResult: 0x%08lx.\n", res);
352 
353     ok(stream.RefCount == 0, "RefCount has a wrong value: %ld (expected %d).\n", stream.RefCount, 0);
354 
355     ok(finalReleaseCallCount == 1, "FinalRelease was called %lu times instead of 1.\n", finalReleaseCallCount);
356 }
357 
358 void test_OutOfProcess()
359 {
360     LARGE_INTEGER move;
361     ULARGE_INTEGER size;
362     HRESULT res;
363     HANDLE process;
364     ULONG i;
365 
366     RTL_MEMORY_STREAM stream;
367     RTL_MEMORY_STREAM previous;
368 
369     IStream * istream;
370 
371     UCHAR buffer[80];
372     UCHAR buffer2[180];
373     ULONG bytesRead;
374 
375     STATSTG stat;
376 
377     finalReleaseCallCount = 0;
378 
379     for (i = 0; i < sizeof(buffer2); i++)
380     {
381         buffer2[i] = i % UCHAR_MAX;
382     }
383 
384     memset(&stream, 0x90, sizeof(stream));
385     memset(&previous, 0x00, sizeof(previous));
386 
387     process = GetCurrentProcess();
388 
389     RtlInitOutOfProcessMemoryStream(&stream);
390 
391     ok(stream.FinalRelease == RtlFinalReleaseOutOfProcessMemoryStream,
392        "stream.FinalRelease unexpected %p != %p.\n",
393        stream.FinalRelease, RtlFinalReleaseOutOfProcessMemoryStream);
394 
395     ok(stream.RefCount == 0, "RefCount has a wrong value: %ld (expected %d).\n", stream.RefCount, 0);
396 
397     CompareStructsAndSaveForLater(&previous, &stream, "After init");
398 
399     stream.Current = buffer2;
400     stream.Start = buffer2;
401     stream.End = buffer2 + sizeof(buffer2);
402     stream.ProcessHandle = process;
403     stream.FinalRelease = CustomFinalReleaseOutOfProcessMemoryStream;
404 
405     CompareStructsAndSaveForLater(&previous, &stream, "After assigning");
406 
407     res = IStream_QueryInterface((struct IStream*)&stream, &IID_IStream, (void**)&istream);
408 
409     ok(res == S_OK, "QueryInterface to IStream returned wrong hResult: 0x%08lx.\n", res);
410 
411     ok(stream.RefCount == 1, "RefCount has a wrong value: %ld (expected %d).\n", stream.RefCount, 1);
412 
413     ok(stream.ProcessHandle == process,
414        "ProcessHandle changed unexpectedly: 0x%p (expected 0x%p)\n",
415        stream.ProcessHandle, process);
416 
417     CompareStructsAndSaveForLater(&previous, &stream, "After QueryInterface");
418 
419     res = IStream_Stat(istream, &stat, STATFLAG_NONAME);
420 
421     ok(res == S_OK, "Stat to IStream returned wrong hResult: 0x%08lx.\n", res);
422 
423     ok(stream.Current == buffer2,
424        "stream.Current points to the wrong address 0x%p (expected 0x%p)\n",
425        stream.Current, buffer2);
426     ok(stream.Start == buffer2, "stream.Start was changed unexpectedly\n");
427     ok(stream.End == buffer2 + sizeof(buffer2), "stream.End was changed unexpectedly\n");
428     ok(stream.ProcessHandle == process,
429        "ProcessHandle changed unexpectedly: 0x%p (expected 0x%p)\n",
430        stream.ProcessHandle, process);
431 
432     ok(stat.cbSize.QuadPart == ((PUCHAR)stream.End - (PUCHAR)stream.Start),
433        "stat.cbSize has the wrong value %I64u (expected %d)\n",
434        stat.cbSize.QuadPart, (PUCHAR)stream.End - (PUCHAR)stream.Start);
435 
436     CompareStructsAndSaveForLater(&previous, &stream, "After Stat");
437 
438     res = IStream_Read(istream, buffer, sizeof(buffer), &bytesRead);
439 
440     ok(res == S_OK, "Read to IStream returned wrong hResult: 0x%08lx.\n", res);
441 
442     if (SUCCEEDED(res))
443     {
444         for (i = 0; i < bytesRead; i++)
445         {
446             ok(buffer[i] == i, "Buffer[%lu] contains a wrong number %u (expected %lu).\n", i, buffer[i], i);
447         }
448     }
449 
450     ok(stream.Current == buffer2 + sizeof(buffer),
451        "stream.Current points to the wrong address 0x%p (expected 0x%p)\n",
452        stream.Current, buffer2);
453     ok(stream.Start == buffer2, "stream.Start was changed unexpectedly\n");
454     ok(stream.End == buffer2 + sizeof(buffer2), "stream.End was changed unexpectedly\n");
455     ok(stream.ProcessHandle == process,
456        "ProcessHandle changed unexpectedly: 0x%p (expected 0x%p)\n",
457        stream.ProcessHandle, process);
458 
459     CompareStructsAndSaveForLater(&previous, &stream, "After Read 1");
460 
461     move.QuadPart = 40;
462 
463     res = IStream_Seek(istream, move, STREAM_SEEK_SET, &size);
464 
465     ok(res == S_OK, "Seek to IStream returned wrong hResult: 0x%08lx.\n", res);
466 
467     ok(size.QuadPart == 40,
468        "Seek returned wrong offset %I64u (expected %d)\n",
469        size.QuadPart, 40);
470 
471     ok(stream.Current == buffer2 + 40,
472        "stream.Current points to the wrong address 0x%p (expected 0x%p)\n",
473        stream.Current, buffer2);
474     ok(stream.Start == buffer2, "stream.Start was changed unexpectedly\n");
475     ok(stream.End == buffer2 + sizeof(buffer2), "stream.End was changed unexpectedly\n");
476     ok(stream.ProcessHandle == process,
477        "ProcessHandle changed unexpectedly: 0x%p (expected 0x%p)\n",
478        stream.ProcessHandle, process);
479 
480     CompareStructsAndSaveForLater(&previous, &stream, "After Seek");
481 
482     res = IStream_Read(istream, buffer, sizeof(buffer), &bytesRead);
483 
484     ok(res == S_OK, "Read to IStream returned wrong hResult: 0x%08lx.\n", res);
485 
486     if (SUCCEEDED(res))
487     {
488         for (i = 0; i < bytesRead; i++)
489         {
490             ok(buffer[i] == (i + 40), "Buffer[%lu] contains a wrong number %u (expected %lu).\n", i, buffer[i], i + 40);
491         }
492     }
493 
494     ok(stream.Current == buffer2 + 40 + sizeof(buffer),
495        "stream.Current points to the wrong address 0x%p (expected 0x%p)\n",
496        stream.Current, buffer2);
497     ok(stream.Start == buffer2, "stream.Start was changed unexpectedly\n");
498     ok(stream.End == buffer2 + sizeof(buffer2), "stream.End was changed unexpectedly\n");
499     ok(stream.ProcessHandle == process,
500        "ProcessHandle changed unexpectedly: 0x%p (expected 0x%p)\n",
501        stream.ProcessHandle, process);
502 
503     CompareStructsAndSaveForLater(&previous, &stream, "After Read 2");
504 
505     res = IStream_Release(istream);
506 
507     ok(res == S_OK, "Release to IStream returned wrong hResult: 0x%08lx.\n", res);
508 
509     ok(stream.RefCount == 0, "RefCount has a wrong value: %ld (expected %d).\n", stream.RefCount, 0);
510 
511     ok(finalReleaseCallCount == 1, "FinalRelease was called %lu times instead of 1.\n", finalReleaseCallCount);
512 }
513 
514 START_TEST(RtlMemoryStream)
515 {
516     test_InProcess();
517     test_OutOfProcess();
518 }
519