ReactOS  0.4.13-dev-687-g023794c
hglobalstream.c
Go to the documentation of this file.
1 /*
2  * Stream on HGLOBAL Tests
3  *
4  * Copyright 2006 Robert Shearman (for CodeWeavers)
5  * Copyright 2016 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define COBJMACROS
23 
24 #include <stdarg.h>
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
29 
30 #include "wine/test.h"
31 
32 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
33 
34 static char const * const *expected_method_list;
35 
36 #define CHECK_EXPECTED_METHOD(method_name) \
37 do { \
38  ok(*expected_method_list != NULL, "Extra method %s called\n", method_name); \
39  if (*expected_method_list) \
40  { \
41  ok(!strcmp(*expected_method_list, method_name), "Expected %s to be called instead of %s\n", \
42  *expected_method_list, method_name); \
43  expected_method_list++; \
44  } \
45 } while(0)
46 
47 static void test_streamonhglobal(void)
48 {
49  const char data[] = "Test String";
50  ULARGE_INTEGER ull;
51  IStream *pStream;
53  char buffer[128];
54  ULONG read;
55  STATSTG statstg;
56  HRESULT hr;
57 
58  hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
59  ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
60 
61  ull.QuadPart = sizeof(data);
62  hr = IStream_SetSize(pStream, ull);
63  ok_ole_success(hr, "IStream_SetSize");
64 
65  hr = IStream_Write(pStream, data, sizeof(data), NULL);
66  ok_ole_success(hr, "IStream_Write");
67 
68  ll.QuadPart = 0;
69  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, NULL);
70  ok_ole_success(hr, "IStream_Seek");
71 
72  /* should return S_OK, not S_FALSE */
73  hr = IStream_Read(pStream, buffer, sizeof(buffer), &read);
74  ok_ole_success(hr, "IStream_Read");
75  ok(read == sizeof(data), "IStream_Read returned read %d\n", read);
76 
77  /* ignores HighPart */
78  ull.u.HighPart = -1;
79  ull.u.LowPart = 0;
80  hr = IStream_SetSize(pStream, ull);
81  ok_ole_success(hr, "IStream_SetSize");
82 
83  /* IStream_Seek -- NULL position argument */
84  ll.u.HighPart = 0;
85  ll.u.LowPart = 0;
86  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, NULL);
87  ok_ole_success(hr, "IStream_Seek");
88 
89  /* IStream_Seek -- valid position argument (seek from current position) */
90  ull.u.HighPart = 0xCAFECAFE;
91  ull.u.LowPart = 0xCAFECAFE;
92  ll.u.HighPart = 0;
93  ll.u.LowPart = 0;
94  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
95  ok_ole_success(hr, "IStream_Seek");
96  ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart);
97  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
98 
99  /* IStream_Seek -- invalid seek argument */
100  ull.u.HighPart = 0xCAFECAFE;
101  ull.u.LowPart = 0xCAFECAFE;
102  ll.u.HighPart = 0;
103  ll.u.LowPart = 123;
104  hr = IStream_Seek(pStream, ll, STREAM_SEEK_END+1, &ull);
105  ok(hr == STG_E_SEEKERROR, "IStream_Seek should have returned STG_E_SEEKERROR instead of 0x%08x\n", hr);
106  ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart);
107  ok(ull.u.HighPart == 0, "should not have changed HighPart, got %d\n", ull.u.HighPart);
108 
109  /* IStream_Seek -- valid position argument (seek to beginning) */
110  ull.u.HighPart = 0xCAFECAFE;
111  ull.u.LowPart = 0xCAFECAFE;
112  ll.u.HighPart = 0;
113  ll.u.LowPart = 0;
114  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
115  ok_ole_success(hr, "IStream_Seek");
116  ok(ull.u.LowPart == 0, "should have set LowPart to 0 instead of %d\n", ull.u.LowPart);
117  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
118 
119  /* IStream_Seek -- valid position argument (seek to end) */
120  ull.u.HighPart = 0xCAFECAFE;
121  ull.u.LowPart = 0xCAFECAFE;
122  ll.u.HighPart = 0;
123  ll.u.LowPart = 0;
124  hr = IStream_Seek(pStream, ll, STREAM_SEEK_END, &ull);
125  ok_ole_success(hr, "IStream_Seek");
126  ok(ull.u.LowPart == 0, "should have set LowPart to 0 instead of %d\n", ull.u.LowPart);
127  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
128 
129  /* IStream_Seek -- ignore HighPart in the move value (seek from current position) */
130  ll.u.HighPart = 0;
131  ll.u.LowPart = sizeof(data);
132  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
133  ok_ole_success(hr, "IStream_Seek");
134 
135  ull.u.HighPart = 0xCAFECAFE;
136  ull.u.LowPart = 0xCAFECAFE;
137  ll.u.HighPart = -1;
138  ll.u.LowPart = 0;
139  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
140  ok_ole_success(hr, "IStream_Seek");
141  ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart);
142  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
143 
144  /* IStream_Seek -- ignore HighPart in the move value (seek to beginning) */
145  ll.u.HighPart = 0;
146  ll.u.LowPart = sizeof(data);
147  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
148  ok_ole_success(hr, "IStream_Seek");
149 
150  ull.u.HighPart = 0xCAFECAFE;
151  ull.u.LowPart = 0xCAFECAFE;
152  ll.u.HighPart = -1;
153  ll.u.LowPart = 0;
154  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
155  ok_ole_success(hr, "IStream_Seek");
156  ok(ull.u.LowPart == 0, "should have set LowPart to 0 instead of %d\n", ull.u.LowPart);
157  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
158 
159  /* IStream_Seek -- invalid LowPart value (seek before start of stream) */
160  ll.u.HighPart = 0;
161  ll.u.LowPart = sizeof(data);
162  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
163  ok_ole_success(hr, "IStream_Seek");
164 
165  ull.u.HighPart = 0xCAFECAFE;
166  ull.u.LowPart = 0xCAFECAFE;
167  ll.u.HighPart = 0;
168  ll.u.LowPart = 0x80000000;
169  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
170  ok(hr == STG_E_SEEKERROR, "IStream_Seek should have returned STG_E_SEEKERROR instead of 0x%08x\n", hr);
171  ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart);
172  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
173 
174  /* IStream_Seek -- valid LowPart value (seek to start of stream) */
175  ll.u.HighPart = 0;
176  ll.u.LowPart = sizeof(data);
177  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
178  ok_ole_success(hr, "IStream_Seek");
179 
180  ull.u.HighPart = 0xCAFECAFE;
181  ull.u.LowPart = 0xCAFECAFE;
182  ll.u.HighPart = 0;
183  ll.u.LowPart = -(DWORD)sizeof(data);
184  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
185  ok_ole_success(hr, "IStream_Seek");
186  ok(ull.u.LowPart == 0, "LowPart set to %d\n", ull.u.LowPart);
187  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
188 
189  /* IStream_Seek -- invalid LowPart value (seek to start of stream-1) */
190  ll.u.HighPart = 0;
191  ll.u.LowPart = sizeof(data);
192  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
193  ok_ole_success(hr, "IStream_Seek");
194 
195  ull.u.HighPart = 0xCAFECAFE;
196  ull.u.LowPart = 0xCAFECAFE;
197  ll.u.HighPart = 0;
198  ll.u.LowPart = -(DWORD)sizeof(data)-1;
199  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
200  ok(hr == STG_E_SEEKERROR, "IStream_Seek should have returned STG_E_SEEKERROR instead of 0x%08x\n", hr);
201  ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart);
202  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
203 
204  /* IStream_Seek -- valid LowPart value (seek forward to 0x80000000) */
205  ll.u.HighPart = 0;
206  ll.u.LowPart = sizeof(data);
207  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
208  ok_ole_success(hr, "IStream_Seek");
209 
210  ull.u.HighPart = 0xCAFECAFE;
211  ull.u.LowPart = 0xCAFECAFE;
212  ll.u.HighPart = 0;
213  ll.u.LowPart = 0x80000000 - sizeof(data);
214  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
215  ok_ole_success(hr, "IStream_Seek");
216  ok(ull.u.LowPart == 0x80000000, "LowPart set to %d\n", ull.u.LowPart);
217  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
218 
219  /* IStream_Seek -- invalid LowPart value (seek to beginning) */
220  ll.u.HighPart = 0;
221  ll.u.LowPart = sizeof(data);
222  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
223  ok_ole_success(hr, "IStream_Seek");
224 
225  ull.u.HighPart = 0xCAFECAFE;
226  ull.u.LowPart = 0xCAFECAFE;
227  ll.u.HighPart = 0;
228  ll.u.LowPart = 0x80000000;
229  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
230  ok(hr == STG_E_SEEKERROR, "IStream_Seek should have returned STG_E_SEEKERROR instead of 0x%08x\n", hr);
231  ok(ull.u.LowPart == sizeof(data), "LowPart set to %d\n", ull.u.LowPart);
232  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
233 
234  /* IStream_Seek -- valid LowPart value (seek to beginning) */
235  ull.u.HighPart = 0xCAFECAFE;
236  ull.u.LowPart = 0xCAFECAFE;
237  ll.u.HighPart = 0;
238  ll.u.LowPart = 0x7FFFFFFF;
239  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
240  ok_ole_success(hr, "IStream_Seek");
241  ok(ull.u.LowPart == 0x7FFFFFFF, "should have set LowPart to 0x7FFFFFFF instead of %08x\n", ull.u.LowPart);
242  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
243 
244  /* IStream_Seek -- valid LowPart value (seek from current position) */
245  ll.u.HighPart = 0;
246  ll.u.LowPart = 0;
247  hr = IStream_Seek(pStream, ll, STREAM_SEEK_SET, &ull);
248  ok_ole_success(hr, "IStream_Seek");
249 
250  ull.u.HighPart = 0xCAFECAFE;
251  ull.u.LowPart = 0xCAFECAFE;
252  ll.u.HighPart = 0;
253  ll.u.LowPart = 0x7FFFFFFF;
254  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
255  ok_ole_success(hr, "IStream_Seek");
256  ok(ull.u.LowPart == 0x7FFFFFFF, "should have set LowPart to 0x7FFFFFFF instead of %08x\n", ull.u.LowPart);
257  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
258 
259  /* IStream_Seek -- second seek allows you to go past 0x7FFFFFFF size */
260  ull.u.HighPart = 0xCAFECAFE;
261  ull.u.LowPart = 0xCAFECAFE;
262  ll.u.HighPart = 0;
263  ll.u.LowPart = 9;
264  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
265  ok_ole_success(hr, "IStream_Seek");
266  ok(ull.u.LowPart == 0x80000008, "should have set LowPart to 0x80000008 instead of %08x\n", ull.u.LowPart);
267  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
268 
269  /* IStream_Seek -- seek wraps position/size on integer overflow, but not on win8 */
270  ull.u.HighPart = 0xCAFECAFE;
271  ull.u.LowPart = 0xCAFECAFE;
272  ll.u.HighPart = 0;
273  ll.u.LowPart = 0x7FFFFFFF;
274  hr = IStream_Seek(pStream, ll, STREAM_SEEK_CUR, &ull);
275  ok(hr == S_OK || hr == STG_E_SEEKERROR /* win8 */, "IStream_Seek\n");
276  if (SUCCEEDED(hr))
277  ok(ull.u.LowPart == 0x00000007, "should have set LowPart to 0x00000007 instead of %08x\n", ull.u.LowPart);
278  else
279  ok(ull.u.LowPart == 0x80000008, "should have set LowPart to 0x80000008 instead of %08x\n", ull.u.LowPart);
280  ok(ull.u.HighPart == 0, "should have set HighPart to 0 instead of %d\n", ull.u.HighPart);
281 
282  hr = IStream_Commit(pStream, STGC_DEFAULT);
283  ok_ole_success(hr, "IStream_Commit");
284 
285  hr = IStream_Revert(pStream);
286  ok_ole_success(hr, "IStream_Revert");
287 
288  hr = IStream_LockRegion(pStream, ull, ull, LOCK_WRITE);
289  ok(hr == STG_E_INVALIDFUNCTION, "IStream_LockRegion should have returned STG_E_INVALIDFUNCTION instead of 0x%08x\n", hr);
290 
291  hr = IStream_Stat(pStream, &statstg, STATFLAG_DEFAULT);
292  ok_ole_success(hr, "IStream_Stat");
293  ok(statstg.type == STGTY_STREAM, "statstg.type should have been STGTY_STREAM instead of %d\n", statstg.type);
294 
295  /* test OOM condition */
296  ull.u.HighPart = -1;
297  ull.u.LowPart = -1;
298  hr = IStream_SetSize(pStream, ull);
299  ok(hr == E_OUTOFMEMORY || broken(hr == S_OK), /* win9x */
300  "IStream_SetSize with large size should have returned E_OUTOFMEMORY instead of 0x%08x\n", hr);
301 
302  IStream_Release(pStream);
303 }
304 
306 {
307  if (IsEqualIID(riid, &IID_IUnknown) ||
308  IsEqualIID(riid, &IID_ISequentialStream) ||
309  IsEqualIID(riid, &IID_IStream))
310  {
311  *ppv = iface;
312  IStream_AddRef(iface);
313  return S_OK;
314  }
315  *ppv = NULL;
316  return E_NOINTERFACE;
317 }
318 
320 {
321  return 2;
322 }
323 
325 {
326  return 1;
327 }
328 
329 static HRESULT WINAPI TestStream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
330 {
331  CHECK_EXPECTED_METHOD("TestStream_Read");
332  return E_NOTIMPL;
333 }
334 
335 static HRESULT WINAPI TestStream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
336 {
337  CHECK_EXPECTED_METHOD("TestStream_Write");
338  *pcbWritten = 5;
339  return S_OK;
340 }
341 
342 static HRESULT WINAPI TestStream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
343 {
344  CHECK_EXPECTED_METHOD("TestStream_Seek");
345  return E_NOTIMPL;
346 }
347 
349 {
350  CHECK_EXPECTED_METHOD("TestStream_SetSize");
351  return E_NOTIMPL;
352 }
353 
355 {
356  CHECK_EXPECTED_METHOD("TestStream_CopyTo");
357  return E_NOTIMPL;
358 }
359 
360 static HRESULT WINAPI TestStream_Commit(IStream *iface, DWORD grfCommitFlags)
361 {
362  CHECK_EXPECTED_METHOD("TestStream_Commit");
363  return E_NOTIMPL;
364 }
365 
367 {
368  CHECK_EXPECTED_METHOD("TestStream_Revert");
369  return E_NOTIMPL;
370 }
371 
373 {
374  CHECK_EXPECTED_METHOD("TestStream_LockRegion");
375  return E_NOTIMPL;
376 }
377 
379 {
380  CHECK_EXPECTED_METHOD("TestStream_UnlockRegion");
381  return E_NOTIMPL;
382 }
383 
384 static HRESULT WINAPI TestStream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
385 {
386  CHECK_EXPECTED_METHOD("TestStream_Stat");
387  return E_NOTIMPL;
388 }
389 
390 static HRESULT WINAPI TestStream_Clone(IStream *iface, IStream **pStream)
391 {
392  CHECK_EXPECTED_METHOD("TestStream_Clone");
393  return E_NOTIMPL;
394 }
395 
396 static /*const*/ IStreamVtbl StreamVtbl =
397 {
412 };
413 
415 
416 static void test_copyto(void)
417 {
418  IStream *pStream, *pStream2;
419  HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
420  static const char szHello[] = "Hello";
422  static const char *methods_copyto[] =
423  {
424  "TestStream_Write",
425  NULL
426  };
427  ULONG written;
428  ULARGE_INTEGER ullRead;
429  ULARGE_INTEGER ullWritten;
430  ULARGE_INTEGER libNewPosition;
431  static const LARGE_INTEGER llZero;
432  char buffer[15];
433 
434  ok_ole_success(hr, "CreateStreamOnHGlobal");
435 
436  expected_method_list = methods_copyto;
437 
438  hr = IStream_Write(pStream, szHello, sizeof(szHello), &written);
439  ok_ole_success(hr, "IStream_Write");
440  ok(written == sizeof(szHello), "only %d bytes written\n", written);
441 
442  hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
443  ok_ole_success(hr, "IStream_Seek");
444 
445  cb.QuadPart = sizeof(szHello);
446  hr = IStream_CopyTo(pStream, &Test_Stream, cb, &ullRead, &ullWritten);
447  ok(ullWritten.QuadPart == 5, "ullWritten was %d instead\n", (ULONG)ullWritten.QuadPart);
448  ok(ullRead.QuadPart == sizeof(szHello), "only %d bytes read\n", (ULONG)ullRead.QuadPart);
449  ok_ole_success(hr, "IStream_CopyTo");
450 
451  ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
452 
453  hr = IStream_Clone(pStream, &pStream2);
454  ok_ole_success(hr, "IStream_Clone");
455 
456  hr = IStream_Seek(pStream2, llZero, STREAM_SEEK_CUR, &libNewPosition);
457  ok_ole_success(hr, "IStream_Seek");
458  ok(libNewPosition.QuadPart == sizeof(szHello), "libNewPosition wasn't set correctly for the cloned stream\n");
459 
460  hr = IStream_Seek(pStream2, llZero, STREAM_SEEK_SET, NULL);
461  ok_ole_success(hr, "IStream_Seek");
462 
463  hr = IStream_Read(pStream2, buffer, sizeof(buffer), NULL);
464  ok_ole_success(hr, "IStream_Read");
465  ok(!strcmp(buffer, szHello), "read data \"%s\" didn't match originally written data\n", buffer);
466 
467  IStream_Release(pStream2);
468  IStream_Release(pStream);
469 }
470 
471 static void test_freed_hglobal(void)
472 {
473  static const char teststring[] = "this is a test string";
474  HRESULT hr;
475  IStream *pStream;
477  char *p;
478  char buffer[sizeof(teststring) + 8];
479  ULARGE_INTEGER ull;
480  ULONG read, written;
481 
483  ok(hglobal != NULL, "GlobalAlloc failed with error %d\n", GetLastError());
484  p = GlobalLock(hglobal);
485  strcpy(p, teststring);
487 
488  hr = CreateStreamOnHGlobal(hglobal, FALSE, &pStream);
489  ok_ole_success(hr, "CreateStreamOnHGlobal");
490 
491  hr = IStream_Read(pStream, buffer, sizeof(buffer), &read);
492  ok_ole_success(hr, "IStream_Read");
493  ok(!strcmp(buffer, teststring), "buffer data %s differs\n", buffer);
494  ok(read == sizeof(teststring) ||
495  broken(read == ((sizeof(teststring) + 3) & ~3)), /* win9x rounds the size */
496  "read should be sizeof(teststring) instead of %d\n", read);
497 
499 
500  memset(buffer, 0, sizeof(buffer));
501  read = -1;
502  hr = IStream_Read(pStream, buffer, sizeof(buffer), &read);
503  ok_ole_success(hr, "IStream_Read");
504  ok(buffer[0] == 0, "buffer data should be untouched\n");
505  ok(read == 0, "read should be 0 instead of %d\n", read);
506 
507  ull.QuadPart = sizeof(buffer);
508  hr = IStream_SetSize(pStream, ull);
509  ok(hr == E_OUTOFMEMORY, "IStream_SetSize with invalid HGLOBAL should return E_OUTOFMEMORY instead of 0x%08x\n", hr);
510 
511  hr = IStream_Write(pStream, buffer, sizeof(buffer), &written);
512  ok(hr == E_OUTOFMEMORY, "IStream_Write with invalid HGLOBAL should return E_OUTOFMEMORY instead of 0x%08x\n", hr);
513  ok(written == 0, "written should be 0 instead of %d\n", written);
514 
515  IStream_Release(pStream);
516 }
517 
518 static void stream_info(IStream *stream, HGLOBAL *hmem, int *size, int *pos)
519 {
520  HRESULT hr;
521  STATSTG stat;
523  ULARGE_INTEGER newpos;
524 
525  *hmem = 0;
526  *size = *pos = -1;
527 
528  hr = GetHGlobalFromStream(stream, hmem);
529  ok(hr == S_OK, "unexpected %#x\n", hr);
530 
531  memset(&stat, 0x55, sizeof(stat));
532  hr = IStream_Stat(stream, &stat, STATFLAG_DEFAULT);
533  ok(hr == S_OK, "unexpected %#x\n", hr);
534  ok(stat.type == STGTY_STREAM, "unexpected %#x\n", stat.type);
535  ok(!stat.pwcsName, "unexpected %p\n", stat.pwcsName);
536  ok(IsEqualIID(&stat.clsid, &GUID_NULL), "unexpected %s\n", wine_dbgstr_guid(&stat.clsid));
537  ok(!stat.cbSize.HighPart, "unexpected %#x\n", stat.cbSize.HighPart);
538  *size = stat.cbSize.LowPart;
539 
540  offset.QuadPart = 0;
541  hr = IStream_Seek(stream, offset, STREAM_SEEK_CUR, &newpos);
542  ok(hr == S_OK, "unexpected %#x\n", hr);
543  ok(!newpos.HighPart, "unexpected %#x\n", newpos.HighPart);
544  *pos = newpos.LowPart;
545 }
546 
547 static void test_IStream_Clone(void)
548 {
549  static const char hello[] = "Hello World!";
550  char buf[32];
551  HRESULT hr;
552  IStream *stream, *clone;
553  HGLOBAL orig_hmem, hmem, hmem_clone;
554  ULARGE_INTEGER newsize;
556  int size, pos, ret;
557 
558  /* test simple case for Clone */
559  orig_hmem = GlobalAlloc(GMEM_MOVEABLE, 0);
560  ok(orig_hmem != 0, "unexpected %p\n", orig_hmem);
561  hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
562  ok(hr == S_OK, "unexpected %#x\n", hr);
563 
565  ok(hr == E_INVALIDARG, "unexpected %#x\n", hr);
566 
567  hr = GetHGlobalFromStream(NULL, &hmem);
568  ok(hr == E_INVALIDARG, "unexpected %#x\n", hr);
569 
570  stream_info(stream, &hmem, &size, &pos);
571  ok(hmem == orig_hmem, "handles should match\n");
572  ok(size == 0, "unexpected %d\n", size);
573  ok(pos == 0, "unexpected %d\n", pos);
574 
575  hr = IStream_Clone(stream, &clone);
576  ok(hr == S_OK, "unexpected %#x\n", hr);
577 
578  hr = IStream_Write(stream, hello, sizeof(hello), NULL);
579  ok(hr == S_OK, "unexpected %#x\n", hr);
580 
581  stream_info(stream, &hmem, &size, &pos);
582  ok(hmem != 0, "unexpected %p\n", hmem);
583  ok(size == 13, "unexpected %d\n", size);
584  ok(pos == 13, "unexpected %d\n", pos);
585 
586  stream_info(clone, &hmem_clone, &size, &pos);
587  ok(hmem_clone == hmem, "handles should match\n");
588  ok(size == 13, "unexpected %d\n", size);
589  ok(pos == 0, "unexpected %d\n", pos);
590 
591  buf[0] = 0;
592  hr = IStream_Read(clone, buf, sizeof(buf), NULL);
593  ok(hr == S_OK, "unexpected %#x\n", hr);
594  ok(!strcmp(buf, hello), "wrong stream contents\n");
595 
596  newsize.QuadPart = 0x8000;
597  hr = IStream_SetSize(stream, newsize);
598  ok(hr == S_OK, "unexpected %#x\n", hr);
599 
600  stream_info(stream, &hmem, &size, &pos);
601  ok(hmem != 0, "unexpected %p\n", hmem);
602  ok(hmem == orig_hmem, "unexpected %p\n", hmem);
603  ok(size == 0x8000, "unexpected %#x\n", size);
604  ok(pos == 13, "unexpected %d\n", pos);
605 
606  stream_info(clone, &hmem_clone, &size, &pos);
607  ok(hmem_clone == hmem, "handles should match\n");
608  ok(size == 0x8000, "unexpected %#x\n", size);
609  ok(pos == 13, "unexpected %d\n", pos);
610 
611  IStream_Release(clone);
612  IStream_Release(stream);
613 
614  /* exploit GMEM_FIXED forced move for the same base streams */
615  orig_hmem = GlobalAlloc(GMEM_FIXED, 1);
616  ok(orig_hmem != 0, "unexpected %p\n", orig_hmem);
617  hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
618  ok(hr == S_OK, "unexpected %#x\n", hr);
619 
620  hr = IStream_Clone(stream, &clone);
621  ok(hr == S_OK, "unexpected %#x\n", hr);
622 
623  stream_info(stream, &hmem, &size, &pos);
624  ok(hmem != 0, "unexpected %p\n", hmem);
625  ok(size == 1, "unexpected %d\n", size);
626  ok(pos == 0, "unexpected %d\n", pos);
627 
628  stream_info(clone, &hmem_clone, &size, &pos);
629  ok(hmem_clone == hmem, "handles should match\n");
630  ok(size == 1, "unexpected %d\n", size);
631  ok(pos == 0, "unexpected %d\n", pos);
632 
633  newsize.QuadPart = 0x8000;
634  hr = IStream_SetSize(stream, newsize);
635  ok(hr == S_OK, "unexpected %#x\n", hr);
636 
637  stream_info(stream, &hmem, &size, &pos);
638  ok(hmem != 0, "unexpected %p\n", hmem);
639  ok(hmem != orig_hmem, "unexpected %p\n", hmem);
640  ok(size == 0x8000, "unexpected %#x\n", size);
641  ok(pos == 0, "unexpected %d\n", pos);
642 
643  stream_info(clone, &hmem_clone, &size, &pos);
644  ok(hmem_clone == hmem, "handles should match\n");
645  ok(size == 0x8000, "unexpected %#x\n", size);
646  ok(pos == 0, "unexpected %d\n", pos);
647 
648  IStream_Release(stream);
649  IStream_Release(clone);
650 
651  /* exploit GMEM_FIXED forced move for different base streams */
652  orig_hmem = GlobalAlloc(GMEM_FIXED, 1);
653  ok(orig_hmem != 0, "unexpected %p\n", orig_hmem);
654  hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &stream);
655  ok(hr == S_OK, "unexpected %#x\n", hr);
656 
657  hr = CreateStreamOnHGlobal(orig_hmem, TRUE, &clone);
658  ok(hr == S_OK, "unexpected %#x\n", hr);
659 
660  stream_info(stream, &hmem, &size, &pos);
661  ok(hmem != 0, "unexpected %p\n", hmem);
662  ok(size == 1, "unexpected %d\n", size);
663  ok(pos == 0, "unexpected %d\n", pos);
664 
665  stream_info(clone, &hmem_clone, &size, &pos);
666  ok(hmem_clone == hmem, "handles should match\n");
667  ok(size == 1, "unexpected %d\n", size);
668  ok(pos == 0, "unexpected %d\n", pos);
669 
670  newsize.QuadPart = 0x8000;
671  hr = IStream_SetSize(stream, newsize);
672  ok(hr == S_OK, "unexpected %#x\n", hr);
673 
674  stream_info(stream, &hmem, &size, &pos);
675  ok(hmem != 0, "unexpected %p\n", hmem);
676  ok(hmem != orig_hmem, "unexpected %p\n", hmem);
677  ok(size == 0x8000, "unexpected %#x\n", size);
678  ok(pos == 0, "unexpected %d\n", pos);
679 
680  stream_info(clone, &hmem_clone, &size, &pos);
681  ok(hmem_clone != hmem, "handles should not match\n");
682  ok(size == 1, "unexpected %#x\n", size);
683  ok(pos == 0, "unexpected %d\n", pos);
684 
685  IStream_Release(stream);
686  /* releasing clone leads to test termination under windows
687  IStream_Release(clone);
688  */
689 
690  /* test Release for a being cloned stream */
692  ok(hr == S_OK, "unexpected %#x\n", hr);
693 
694  hr = IStream_Clone(stream, &clone);
695  ok(hr == S_OK, "unexpected %#x\n", hr);
696 
697  stream_info(stream, &hmem, &size, &pos);
698  ok(hmem != 0, "unexpected %p\n", hmem);
699  ok(size == 0, "unexpected %d\n", size);
700  ok(pos == 0, "unexpected %d\n", pos);
701 
702  stream_info(clone, &hmem_clone, &size, &pos);
703  ok(hmem_clone == hmem, "handles should match\n");
704  ok(size == 0, "unexpected %#x\n", size);
705  ok(pos == 0, "unexpected %d\n", pos);
706 
707  ret = IStream_Release(stream);
708  ok(ret == 0, "unexpected %d\n", ret);
709 
710  newsize.QuadPart = 0x8000;
711  hr = IStream_SetSize(clone, newsize);
712  ok(hr == S_OK, "unexpected %#x\n", hr);
713 
714  stream_info(clone, &hmem_clone, &size, &pos);
715  ok(hmem_clone == hmem, "handles should match\n");
716  ok(size == 0x8000, "unexpected %#x\n", size);
717  ok(pos == 0, "unexpected %d\n", pos);
718 
719  hr = IStream_Write(clone, hello, sizeof(hello), NULL);
720  ok(hr == S_OK, "unexpected %#x\n", hr);
721 
722  stream_info(clone, &hmem_clone, &size, &pos);
723  ok(hmem_clone == hmem, "handles should match\n");
724  ok(size == 0x8000, "unexpected %#x\n", size);
725  ok(pos == 13, "unexpected %d\n", pos);
726 
727  offset.QuadPart = 0;
728  hr = IStream_Seek(clone, offset, STREAM_SEEK_SET, NULL);
729  ok(hr == S_OK, "unexpected %#x\n", hr);
730 
731  buf[0] = 0;
732  hr = IStream_Read(clone, buf, sizeof(buf), NULL);
733  ok(hr == S_OK, "unexpected %#x\n", hr);
734  ok(!strcmp(buf, hello), "wrong stream contents\n");
735 
736  stream_info(clone, &hmem_clone, &size, &pos);
737  ok(hmem_clone == hmem, "handles should match\n");
738  ok(size == 0x8000, "unexpected %#x\n", size);
739  ok(pos == 32, "unexpected %d\n", pos);
740 
741  ret = IStream_Release(clone);
742  ok(ret == 0, "unexpected %d\n", ret);
743 }
744 
745 START_TEST(hglobalstream)
746 {
748  test_copyto();
751 }
static HRESULT WINAPI TestStream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
struct _ULARGE_INTEGER::@3744 u
#define REFIID
Definition: guiddef.h:118
#define TRUE
Definition: types.h:120
HGLOBAL NTAPI GlobalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:368
HRESULT WINAPI GetHGlobalFromStream(IStream *pstm, HGLOBAL *phglobal)
#define E_NOINTERFACE
Definition: winerror.h:2364
#define CHECK_EXPECTED_METHOD(method_name)
Definition: hglobalstream.c:36
HRESULT hr
Definition: shlfolder.c:183
#define GMEM_NODISCARD
Definition: winbase.h:299
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
static HRESULT WINAPI TestStream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
REFIID riid
Definition: precomp.h:44
GLintptr offset
Definition: glext.h:5920
static HRESULT WINAPI TestStream_Clone(IStream *iface, IStream **pStream)
REFIID LPVOID * ppv
Definition: atlbase.h:39
static HRESULT WINAPI TestStream_Revert(IStream *iface)
#define ok_ole_success(hr, func)
Definition: hglobalstream.c:32
const char * wine_dbgstr_guid(const GUID *guid)
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
$ULONG LowPart
Definition: ntbasedef.h:576
GLuint buffer
Definition: glext.h:5915
static HRESULT WINAPI TestStream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
HRESULT WINAPI CreateStreamOnHGlobal(HGLOBAL hGlobal, BOOL fDeleteOnRelease, LPSTREAM *ppstm)
static HRESULT WINAPI TestStream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
static HRESULT WINAPI TestStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
static ULONG WINAPI TestStream_AddRef(IStream *iface)
Definition: ctx.idl:6
#define DWORD
Definition: nt_native.h:44
static void test_streamonhglobal(void)
Definition: hglobalstream.c:47
static void stream_info(IStream *stream, HGLOBAL *hmem, int *size, int *pos)
static void test_copyto(void)
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define ok(value,...)
#define E_INVALIDARG
Definition: ddrawi.h:101
smooth NULL
Definition: ftsmooth.c:416
static const LARGE_INTEGER llZero
Definition: moniker.c:1113
static HRESULT WINAPI TestStream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
#define STG_E_INVALIDFUNCTION
Definition: winerror.h:2564
static HRESULT WINAPI TestStream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
static HRESULT WINAPI TestStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
static IStream Test_Stream
$ULONG HighPart
Definition: ntbasedef.h:577
GLsizeiptr size
Definition: glext.h:5919
static void test_freed_hglobal(void)
LONG HRESULT
Definition: typedefs.h:77
const GUID IID_IUnknown
#define WINAPI
Definition: msvc.h:8
static ULONG WINAPI TestStream_Release(IStream *iface)
unsigned long DWORD
Definition: ntddk_ex.h:95
HGLOBAL NTAPI GlobalFree(HGLOBAL hMem)
Definition: heapmem.c:611
static DWORD cb
Definition: integrity.c:41
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
int ret
LPVOID NTAPI GlobalLock(HGLOBAL hMem)
Definition: heapmem.c:755
Definition: parse.h:22
#define GMEM_FIXED
Definition: winbase.h:290
GLuint GLuint stream
Definition: glext.h:7522
Definition: stat.h:55
#define GUID_NULL
Definition: ks.h:106
#define broken(x)
Definition: _sntprintf.h:21
_CRTIMP int __cdecl stat(const char *_Filename, struct stat *_Stat)
Definition: stat.h:345
#define S_OK
Definition: intsafe.h:59
static HRESULT WINAPI TestStream_Commit(IStream *iface, DWORD grfCommitFlags)
#define E_NOTIMPL
Definition: ddrawi.h:99
static char const *const * expected_method_list
Definition: hglobalstream.c:34
w ll
Definition: byte_order.h:166
BOOL NTAPI GlobalUnlock(HGLOBAL hMem)
Definition: heapmem.c:1190
#define GMEM_DDESHARE
Definition: winbase.h:295
static IStreamVtbl StreamVtbl
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
unsigned int ULONG
Definition: retypes.h:1
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
GLfloat GLfloat p
Definition: glext.h:8902
#define memset(x, y, z)
Definition: compat.h:39
static HRESULT WINAPI TestStream_CopyTo(IStream *iface, IStream *pStream, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
#define STG_E_SEEKERROR
Definition: winerror.h:2574
#define GMEM_MOVEABLE
Definition: winbase.h:291
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
#define SUCCEEDED(hr)
Definition: intsafe.h:57
START_TEST(hglobalstream)
static void test_IStream_Clone(void)