kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[wine] / dlls / oleaut32 / tests / olepicture.c
1 /*
2  * OLEPICTURE test program
3  *
4  * Copyright 2005 Marcus Meissner
5  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <math.h>
25 #include <float.h>
26 #include <time.h>
27
28 #define COBJMACROS
29
30 #include <wine/test.h>
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winuser.h>
34 #include <wingdi.h>
35 #include <winnls.h>
36 #include <winerror.h>
37 #include <winnt.h>
38
39 #include <wtypes.h>
40 #include <olectl.h>
41 #include <objidl.h>
42
43 static HMODULE hOleaut32;
44
45 static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);
46
47 /* 1x1 pixel gif */
48 static const unsigned char gifimage[35] = {
49 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
50 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
51 0x01,0x00,0x3b
52 };
53
54 /* 1x1 pixel jpg */
55 static const unsigned char jpgimage[285] = {
56 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
57 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
58 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
59 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
60 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
61 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
62 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
63 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
64 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
65 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
66 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
67 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
68 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
69 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
70 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
71 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
72 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
73 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
74 };
75
76 #if 0 /* no png support yet */
77 /* 1x1 pixel png */
78 static const unsigned char pngimage[285] = {
79 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
80 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
81 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
82 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
83 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
84 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
85 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
86 };
87 #endif
88
89 /* 1x1 pixel bmp */
90 static const unsigned char bmpimage[66] = {
91 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
92 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
93 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
94 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
95 0x00,0x00
96 };
97
98 /* 2x2 pixel gif */
99 static const unsigned char gif4pixel[42] = {
100 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
101 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
102 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
103 };
104
105 struct NoStatStreamImpl
106 {
107         const IStreamVtbl       *lpVtbl;   
108         LONG                    ref;
109
110         HGLOBAL                 supportHandle;
111         ULARGE_INTEGER          streamSize;
112         ULARGE_INTEGER          currentPosition;
113 };
114 typedef struct NoStatStreamImpl NoStatStreamImpl;
115 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal);
116
117 static void
118 test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
119 {
120         IPicture*       pic = NULL;
121         HRESULT         hres;
122         LPVOID          pvObj = NULL;
123         OLE_HANDLE      handle, hPal;
124         OLE_XSIZE_HIMETRIC      width;
125         OLE_YSIZE_HIMETRIC      height;
126         short           type;
127         DWORD           attr;
128         ULONG           res;
129
130         pvObj = NULL;
131         hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
132         pic = pvObj;
133
134         ok(hres == S_OK,"OLP (NULL,..) does not return 0, but 0x%08lx\n",hres);
135         ok(pic != NULL,"OLP (NULL,..) returns NULL, instead of !NULL\n");
136         if (pic == NULL)
137                 return;
138
139         pvObj = NULL;
140         hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);
141
142         ok(hres == S_OK,"IPicture_QI does not return S_OK, but 0x%08lx\n", hres);
143         ok(pvObj != NULL,"IPicture_QI does return NULL, instead of a ptr\n");
144
145         IPicture_Release ((IPicture*)pvObj);
146
147         handle = 0;
148         hres = IPicture_get_Handle (pic, &handle);
149         ok(hres == S_OK,"IPicture_get_Handle does not return S_OK, but 0x%08lx\n", hres);
150         ok(handle != 0, "IPicture_get_Handle returns a NULL handle, but it should be non NULL\n");
151
152         width = 0;
153         hres = IPicture_get_Width (pic, &width);
154         ok(hres == S_OK,"IPicture_get_Width does not return S_OK, but 0x%08lx\n", hres);
155         ok(width != 0, "IPicture_get_Width returns 0, but it should not be 0.\n");
156
157         height = 0;
158         hres = IPicture_get_Height (pic, &height);
159         ok(hres == S_OK,"IPicture_get_Height does not return S_OK, but 0x%08lx\n", hres);
160         ok(height != 0, "IPicture_get_Height returns 0, but it should not be 0.\n");
161
162         type = 0;
163         hres = IPicture_get_Type (pic, &type);
164         ok(hres == S_OK,"IPicture_get_Type does not return S_OK, but 0x%08lx\n", hres);
165         ok(type == PICTYPE_BITMAP, "IPicture_get_Type returns %d, but it should be PICTYPE_BITMAP(%d).\n", type, PICTYPE_BITMAP);
166
167         attr = 0;
168         hres = IPicture_get_Attributes (pic, &attr);
169         ok(hres == S_OK,"IPicture_get_Attributes does not return S_OK, but 0x%08lx\n", hres);
170         ok(attr == 0, "IPicture_get_Attributes returns %ld, but it should be 0.\n", attr);
171
172         hPal = 0;
173         hres = IPicture_get_hPal (pic, &hPal);
174         ok(hres == S_OK,"IPicture_get_hPal does not return S_OK, but 0x%08lx\n", hres);
175         /* a single pixel b/w image has no palette */
176         ok(hPal == 0, "IPicture_get_hPal returns %ld, but it should be 0.\n", (long)hPal);
177
178         res = IPicture_Release (pic);
179         ok (res == 0, "refcount after release is %ld, but should be 0?\n", res);
180 }
181
182 static void
183 test_pic(const unsigned char *imgdata, unsigned int imgsize)
184 {
185         LPSTREAM        stream;
186         HGLOBAL         hglob;
187         LPBYTE          data;
188         HRESULT         hres;
189         LARGE_INTEGER   seekto;
190         ULARGE_INTEGER  newpos1;
191
192         /* Let the fun begin */
193         hglob = GlobalAlloc (0, imgsize);
194         data = GlobalLock (hglob);
195         memcpy(data, imgdata, imgsize);
196
197         hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
198         ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08lx\n", hres);
199
200         memset(&seekto,0,sizeof(seekto));
201         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
202         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
203         test_pic_with_stream(stream, imgsize);
204
205         /* again with Non Statable and Non Seekable stream */
206         stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
207         test_pic_with_stream(stream, 0);
208 }
209
210 static void test_empty_image(void) {
211         LPBYTE          data;
212         LPSTREAM        stream;
213         IPicture*       pic = NULL;
214         HRESULT         hres;
215         LPVOID          pvObj = NULL;
216         HGLOBAL         hglob;
217         OLE_HANDLE      handle;
218         ULARGE_INTEGER  newpos1;
219         LARGE_INTEGER   seekto;
220         short           type;
221
222         /* Empty image. Happens occasionally in VB programs. */
223         hglob = GlobalAlloc (0, 8);
224         data = GlobalLock (hglob);
225         memcpy(data,"lt\0\0",4);
226         ((DWORD*)data)[1] = 0;
227         hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
228         ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08lx\n", hres);
229
230         memset(&seekto,0,sizeof(seekto));
231         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
232         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
233
234         pvObj = NULL;
235         hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
236         pic = pvObj;
237         ok(hres == S_OK,"empty picture not loaded, hres 0x%08lx\n", hres);
238         ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
239
240         hres = IPicture_get_Type (pic, &type);
241         ok (hres == S_OK,"empty picture get type failed with hres 0x%08lx\n", hres);
242         ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
243
244         hres = IPicture_get_Handle (pic, &handle);
245         ok (hres == S_OK,"empty picture get handle failed with hres 0x%08lx\n", hres);
246         ok (handle == 0, "empty picture get handle did not return 0, but 0x%08x\n", handle);
247         IPicture_Release (pic);
248 }
249
250 static void test_empty_image_2(void) {
251         LPBYTE          data;
252         LPSTREAM        stream;
253         IPicture*       pic = NULL;
254         HRESULT         hres;
255         LPVOID          pvObj = NULL;
256         HGLOBAL         hglob;
257         ULARGE_INTEGER  newpos1;
258         LARGE_INTEGER   seekto;
259         short           type;
260
261         /* Empty image at random stream position. */
262         hglob = GlobalAlloc (0, 200);
263         data = GlobalLock (hglob);
264         data += 42;
265         memcpy(data,"lt\0\0",4);
266         ((DWORD*)data)[1] = 0;
267         hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
268         ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08lx\n", hres);
269
270         memset(&seekto,0,sizeof(seekto));
271         seekto.u.LowPart = 42;
272         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
273         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
274
275         pvObj = NULL;
276         hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
277         pic = pvObj;
278         ok(hres == S_OK,"empty picture not loaded, hres 0x%08lx\n", hres);
279         ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
280
281         hres = IPicture_get_Type (pic, &type);
282         ok (hres == S_OK,"empty picture get type failed with hres 0x%08lx\n", hres);
283         ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
284
285         IPicture_Release (pic);
286 }
287
288 START_TEST(olepicture)
289 {
290         hOleaut32 = LoadLibraryA("oleaut32.dll");
291         pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
292         if (!pOleLoadPicture)
293             return;
294
295         /* Test regular 1x1 pixel images of gif, jpg, bmp type */
296         test_pic(gifimage, sizeof(gifimage));
297         test_pic(jpgimage, sizeof(jpgimage));
298         test_pic(bmpimage, sizeof(bmpimage));
299         test_pic(gif4pixel, sizeof(gif4pixel));
300         /* No PNG support yet here or in older Windows...
301         test_pic(pngimage, sizeof(pngimage));
302          */
303         test_empty_image();
304         test_empty_image_2();
305 }
306
307
308 /* Helper functions only ... */
309
310
311 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
312 {
313   GlobalFree(This->supportHandle);
314   This->supportHandle=0;
315   HeapFree(GetProcessHeap(), 0, This);
316 }
317
318 static ULONG WINAPI NoStatStreamImpl_AddRef(
319                 IStream* iface)
320 {
321   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
322   return InterlockedIncrement(&This->ref);
323 }
324
325 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
326                   IStream*     iface,
327                   REFIID         riid,        /* [in] */
328                   void**         ppvObject)   /* [iid_is][out] */
329 {
330   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
331   if (ppvObject==0) return E_INVALIDARG;
332   *ppvObject = 0;
333   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
334   {
335     *ppvObject = (IStream*)This;
336   }
337   else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
338   {
339     *ppvObject = (IStream*)This;
340   }
341
342   if ((*ppvObject)==0)
343     return E_NOINTERFACE;
344   NoStatStreamImpl_AddRef(iface);
345   return S_OK;
346 }
347
348 static ULONG WINAPI NoStatStreamImpl_Release(
349                 IStream* iface)
350 {
351   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
352   ULONG newRef = InterlockedDecrement(&This->ref);
353   if (newRef==0)
354     NoStatStreamImpl_Destroy(This);
355   return newRef;
356 }
357
358 static HRESULT WINAPI NoStatStreamImpl_Read(
359                   IStream*     iface,
360                   void*          pv,        /* [length_is][size_is][out] */
361                   ULONG          cb,        /* [in] */
362                   ULONG*         pcbRead)   /* [out] */
363 {
364   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
365   void* supportBuffer;
366   ULONG bytesReadBuffer;
367   ULONG bytesToReadFromBuffer;
368
369   if (pcbRead==0)
370     pcbRead = &bytesReadBuffer;
371   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
372   supportBuffer = GlobalLock(This->supportHandle);
373   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
374   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
375   *pcbRead = bytesToReadFromBuffer;
376   GlobalUnlock(This->supportHandle);
377   if(*pcbRead == cb)
378     return S_OK;
379   return S_FALSE;
380 }
381
382 static HRESULT WINAPI NoStatStreamImpl_Write(
383                   IStream*     iface,
384                   const void*    pv,          /* [size_is][in] */
385                   ULONG          cb,          /* [in] */
386                   ULONG*         pcbWritten)  /* [out] */
387 {
388   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
389   void*          supportBuffer;
390   ULARGE_INTEGER newSize;
391   ULONG          bytesWritten = 0;
392
393   if (pcbWritten == 0)
394     pcbWritten = &bytesWritten;
395   if (cb == 0)
396     return S_OK;
397   newSize.u.HighPart = 0;
398   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
399   if (newSize.u.LowPart > This->streamSize.u.LowPart)
400    IStream_SetSize(iface, newSize);
401
402   supportBuffer = GlobalLock(This->supportHandle);
403   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
404   This->currentPosition.u.LowPart+=cb;
405   *pcbWritten = cb;
406   GlobalUnlock(This->supportHandle);
407   return S_OK;
408 }
409
410 static HRESULT WINAPI NoStatStreamImpl_Seek(
411                   IStream*      iface,
412                   LARGE_INTEGER   dlibMove,         /* [in] */
413                   DWORD           dwOrigin,         /* [in] */
414                   ULARGE_INTEGER* plibNewPosition) /* [out] */
415 {
416   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
417   ULARGE_INTEGER newPosition;
418   switch (dwOrigin)
419   {
420     case STREAM_SEEK_SET:
421       newPosition.u.HighPart = 0;
422       newPosition.u.LowPart = 0;
423       break;
424     case STREAM_SEEK_CUR:
425       newPosition = This->currentPosition;
426       break;
427     case STREAM_SEEK_END:
428       newPosition = This->streamSize;
429       break;
430     default:
431       return STG_E_INVALIDFUNCTION;
432   }
433   if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
434       return STG_E_INVALIDFUNCTION;
435   newPosition.QuadPart += dlibMove.QuadPart;
436   if (plibNewPosition) *plibNewPosition = newPosition;
437   This->currentPosition = newPosition;
438   return S_OK;
439 }
440
441 static HRESULT WINAPI NoStatStreamImpl_SetSize(
442                                      IStream*      iface,
443                                      ULARGE_INTEGER  libNewSize)   /* [in] */
444 {
445   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
446   HGLOBAL supportHandle;
447   if (libNewSize.u.HighPart != 0)
448     return STG_E_INVALIDFUNCTION;
449   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
450     return S_OK;
451   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
452   if (supportHandle == 0)
453     return STG_E_MEDIUMFULL;
454   This->supportHandle = supportHandle;
455   This->streamSize.u.LowPart = libNewSize.u.LowPart;
456   return S_OK;
457 }
458
459 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
460                                     IStream*      iface,
461                                     IStream*      pstm,         /* [unique][in] */
462                                     ULARGE_INTEGER  cb,           /* [in] */
463                                     ULARGE_INTEGER* pcbRead,      /* [out] */
464                                     ULARGE_INTEGER* pcbWritten)   /* [out] */
465 {
466   HRESULT        hr = S_OK;
467   BYTE           tmpBuffer[128];
468   ULONG          bytesRead, bytesWritten, copySize;
469   ULARGE_INTEGER totalBytesRead;
470   ULARGE_INTEGER totalBytesWritten;
471
472   if ( pstm == 0 )
473     return STG_E_INVALIDPOINTER;
474   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
475   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
476
477   while ( cb.u.LowPart > 0 )
478   {
479     if ( cb.u.LowPart >= 128 )
480       copySize = 128;
481     else
482       copySize = cb.u.LowPart;
483     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
484     totalBytesRead.u.LowPart += bytesRead;
485     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
486     totalBytesWritten.u.LowPart += bytesWritten;
487     if (bytesRead != bytesWritten)
488     {
489       hr = STG_E_MEDIUMFULL;
490       break;
491     }
492     if (bytesRead!=copySize)
493       cb.u.LowPart = 0;
494     else
495       cb.u.LowPart -= bytesRead;
496   }
497   if (pcbRead)
498   {
499     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
500     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
501   }
502
503   if (pcbWritten)
504   {
505     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
506     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
507   }
508   return hr;
509 }
510
511 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
512 {
513   return S_OK;
514 }
515 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
516
517 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
518                   IStream*       iface,
519                   ULARGE_INTEGER libOffset,   /* [in] */
520                   ULARGE_INTEGER cb,          /* [in] */
521                   DWORD          dwLockType)  /* [in] */
522 {
523   return S_OK;
524 }
525
526 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
527                   IStream*       iface,
528                   ULARGE_INTEGER libOffset,   /* [in] */
529                   ULARGE_INTEGER cb,          /* [in] */
530                   DWORD          dwLockType)  /* [in] */
531 {
532   return S_OK;
533 }
534
535 static HRESULT WINAPI NoStatStreamImpl_Stat(
536                   IStream*     iface,
537                   STATSTG*     pstatstg,     /* [out] */
538                   DWORD        grfStatFlag)  /* [in] */
539 {
540   return E_NOTIMPL;
541 }
542
543 static HRESULT WINAPI NoStatStreamImpl_Clone(
544                   IStream*     iface,
545                   IStream**    ppstm) /* [out] */
546 {
547   return E_NOTIMPL;
548 }
549 static const IStreamVtbl NoStatStreamImpl_Vtbl;
550
551 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
552 {
553   NoStatStreamImpl* newStream;
554
555   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
556   if (newStream!=0)
557   {
558     newStream->lpVtbl = &NoStatStreamImpl_Vtbl;
559     newStream->ref    = 0;
560     newStream->supportHandle = hGlobal;
561
562     if (!newStream->supportHandle)
563       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
564                                              GMEM_SHARE, 0);
565     newStream->currentPosition.u.HighPart = 0;
566     newStream->currentPosition.u.LowPart = 0;
567     newStream->streamSize.u.HighPart = 0;
568     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
569   }
570   return newStream;
571 }
572
573
574 static const IStreamVtbl NoStatStreamImpl_Vtbl =
575 {
576     NoStatStreamImpl_QueryInterface,
577     NoStatStreamImpl_AddRef,
578     NoStatStreamImpl_Release,
579     NoStatStreamImpl_Read,
580     NoStatStreamImpl_Write,
581     NoStatStreamImpl_Seek,
582     NoStatStreamImpl_SetSize,
583     NoStatStreamImpl_CopyTo,
584     NoStatStreamImpl_Commit,
585     NoStatStreamImpl_Revert,
586     NoStatStreamImpl_LockRegion,
587     NoStatStreamImpl_UnlockRegion,
588     NoStatStreamImpl_Stat,
589     NoStatStreamImpl_Clone
590 };