oleaut32: Calling SetLcid with LOCALE_NEUTRAL is a special case which sets the first...
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <math.h>
25 #include <float.h>
26
27 #define COBJMACROS
28 #define NONAMELESSUNION
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 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
44
45 #define ole_expect(expr, expect) { \
46     HRESULT r = expr; \
47     ok(r == (expect), #expr " returned %x, expected %s (%x)\n", r, #expect, expect); \
48 }
49
50 #define ole_check(expr) ole_expect(expr, S_OK);
51
52 static HMODULE hOleaut32;
53
54 static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);
55 static HRESULT (WINAPI *pOleCreatePictureIndirect)(PICTDESC*,REFIID,BOOL,LPVOID*);
56
57 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
58
59 /* 1x1 pixel gif */
60 static const unsigned char gifimage[35] = {
61 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
62 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
63 0x01,0x00,0x3b
64 };
65
66 /* 1x1 pixel jpg */
67 static const unsigned char jpgimage[285] = {
68 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
69 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
70 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
71 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
72 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
73 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
74 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
75 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
76 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
77 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
78 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
79 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
80 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
81 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
82 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
83 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
84 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
85 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
86 };
87
88 /* 1x1 pixel png */
89 static const unsigned char pngimage[285] = {
90 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
91 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
92 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
93 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
94 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
95 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
96 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
97 };
98
99 /* 1x1 pixel bmp */
100 static const unsigned char bmpimage[66] = {
101 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
102 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
103 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
104 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
105 0x00,0x00
106 };
107
108 /* 2x2 pixel gif */
109 static const unsigned char gif4pixel[42] = {
110 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
111 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
112 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
113 };
114
115 /* APM with an empty metafile with some padding zeros - looks like under Window the
116  * metafile data should be at least 20 bytes */
117 static const unsigned char apmdata[] = {
118 0xd7,0xcd,0xc6,0x9a, 0x00,0x00,0x00,0x00, 0x00,0x00,0xee,0x02, 0xb1,0x03,0xa0,0x05,
119 0x00,0x00,0x00,0x00, 0xee,0x53,0x01,0x00, 0x09,0x00,0x00,0x03, 0x13,0x00,0x00,0x00,
120 0x01,0x00,0x05,0x00, 0x00,0x00,0x00,0x00, 0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
121 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
122 };
123
124 /* MF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
125 static const unsigned char metafile[] = {
126     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
127     0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
128     0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
129     0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
130     0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
131     0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
132     0x00, 0x00
133 };
134
135 /* EMF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
136 static const unsigned char enhmetafile[] = {
137     0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
138     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
140     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141     0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
142     0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
143     0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
144     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146     0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
147     0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
148     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149     0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
150     0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
151     0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
152     0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
154     0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
155     0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
156     0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
157     0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
158     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
160     0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
161     0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
162     0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
163     0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
164     0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
165     0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
166     0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
167     0x14, 0x00, 0x00, 0x00
168 };
169
170
171 struct NoStatStreamImpl
172 {
173         const IStreamVtbl       *lpVtbl;   
174         LONG                    ref;
175
176         HGLOBAL                 supportHandle;
177         ULARGE_INTEGER          streamSize;
178         ULARGE_INTEGER          currentPosition;
179 };
180 typedef struct NoStatStreamImpl NoStatStreamImpl;
181 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal);
182
183 static void
184 test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
185 {
186         IPicture*       pic = NULL;
187         HRESULT         hres;
188         LPVOID          pvObj = NULL;
189         OLE_HANDLE      handle, hPal;
190         OLE_XSIZE_HIMETRIC      width;
191         OLE_YSIZE_HIMETRIC      height;
192         short           type;
193         DWORD           attr;
194         ULONG           res;
195
196         pvObj = NULL;
197         hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
198         pic = pvObj;
199
200         ok(hres == S_OK,"OLP (NULL,..) does not return 0, but 0x%08x\n",hres);
201         ok(pic != NULL,"OLP (NULL,..) returns NULL, instead of !NULL\n");
202         if (pic == NULL)
203                 return;
204
205         pvObj = NULL;
206         hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);
207
208         ok(hres == S_OK,"IPicture_QI does not return S_OK, but 0x%08x\n", hres);
209         ok(pvObj != NULL,"IPicture_QI does return NULL, instead of a ptr\n");
210
211         IPicture_Release ((IPicture*)pvObj);
212
213         handle = 0;
214         hres = IPicture_get_Handle (pic, &handle);
215         ok(hres == S_OK,"IPicture_get_Handle does not return S_OK, but 0x%08x\n", hres);
216         ok(handle != 0, "IPicture_get_Handle returns a NULL handle, but it should be non NULL\n");
217
218         width = 0;
219         hres = IPicture_get_Width (pic, &width);
220         ok(hres == S_OK,"IPicture_get_Width does not return S_OK, but 0x%08x\n", hres);
221         ok(width != 0, "IPicture_get_Width returns 0, but it should not be 0.\n");
222
223         height = 0;
224         hres = IPicture_get_Height (pic, &height);
225         ok(hres == S_OK,"IPicture_get_Height does not return S_OK, but 0x%08x\n", hres);
226         ok(height != 0, "IPicture_get_Height returns 0, but it should not be 0.\n");
227
228         type = 0;
229         hres = IPicture_get_Type (pic, &type);
230         ok(hres == S_OK,"IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
231         ok(type == PICTYPE_BITMAP, "IPicture_get_Type returns %d, but it should be PICTYPE_BITMAP(%d).\n", type, PICTYPE_BITMAP);
232
233         attr = 0;
234         hres = IPicture_get_Attributes (pic, &attr);
235         ok(hres == S_OK,"IPicture_get_Attributes does not return S_OK, but 0x%08x\n", hres);
236         ok(attr == 0, "IPicture_get_Attributes returns %d, but it should be 0.\n", attr);
237
238         hPal = 0;
239         hres = IPicture_get_hPal (pic, &hPal);
240         ok(hres == S_OK,"IPicture_get_hPal does not return S_OK, but 0x%08x\n", hres);
241         /* a single pixel b/w image has no palette */
242         ok(hPal == 0, "IPicture_get_hPal returns %d, but it should be 0.\n", hPal);
243
244         res = IPicture_Release (pic);
245         ok (res == 0, "refcount after release is %d, but should be 0?\n", res);
246 }
247
248 static void
249 test_pic(const unsigned char *imgdata, unsigned int imgsize)
250 {
251         LPSTREAM        stream;
252         HGLOBAL         hglob;
253         LPBYTE          data;
254         HRESULT         hres;
255         LARGE_INTEGER   seekto;
256         ULARGE_INTEGER  newpos1;
257         DWORD *         header;
258         unsigned int    i,j;
259
260         /* Let the fun begin */
261         hglob = GlobalAlloc (0, imgsize);
262         data = GlobalLock (hglob);
263         memcpy(data, imgdata, imgsize);
264         GlobalUnlock(hglob); data = NULL;
265
266         hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
267         ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
268
269         memset(&seekto,0,sizeof(seekto));
270         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
271         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
272         test_pic_with_stream(stream, imgsize);
273         
274         IStream_Release(stream);
275
276         /* again with Non Statable and Non Seekable stream */
277         stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
278         hglob = 0;  /* Non-statable impl always deletes on release */
279         test_pic_with_stream(stream, 0);
280
281         IStream_Release(stream);
282         for (i = 1; i <= 8; i++) {
283                 /* more fun!!! */
284                 hglob = GlobalAlloc (0, imgsize + i * (2 * sizeof(DWORD)));
285                 data = GlobalLock (hglob);
286                 header = (DWORD *)data;
287
288                 /* multiple copies of header */
289                 memcpy(data,"lt\0\0",4);
290                 header[1] = imgsize;
291                 for (j = 2; j <= i; j++) {
292                         memcpy(&(header[2 * (j - 1)]), header, 2 * sizeof(DWORD));
293                 }
294                 memcpy(data + i * (2 * sizeof(DWORD)), imgdata, imgsize);
295                 GlobalUnlock(hglob); data = NULL;
296
297                 hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
298                 ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
299
300                 memset(&seekto,0,sizeof(seekto));
301                 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
302                 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
303                 test_pic_with_stream(stream, imgsize);
304         
305                 IStream_Release(stream);
306
307                 /* again with Non Statable and Non Seekable stream */
308                 stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
309                 hglob = 0;  /* Non-statable impl always deletes on release */
310                 test_pic_with_stream(stream, 0);
311
312                 IStream_Release(stream);
313         }
314 }
315
316 static void test_empty_image(void) {
317         LPBYTE          data;
318         LPSTREAM        stream;
319         IPicture*       pic = NULL;
320         HRESULT         hres;
321         LPVOID          pvObj = NULL;
322         HGLOBAL         hglob;
323         OLE_HANDLE      handle;
324         ULARGE_INTEGER  newpos1;
325         LARGE_INTEGER   seekto;
326         short           type;
327         DWORD           attr;
328
329         /* Empty image. Happens occasionally in VB programs. */
330         hglob = GlobalAlloc (0, 8);
331         data = GlobalLock (hglob);
332         memcpy(data,"lt\0\0",4);
333         ((DWORD*)data)[1] = 0;
334         hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
335         ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
336
337         memset(&seekto,0,sizeof(seekto));
338         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
339         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
340
341         pvObj = NULL;
342         hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
343         pic = pvObj;
344         ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
345         ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
346
347         hres = IPicture_get_Type (pic, &type);
348         ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
349         ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
350
351         attr = 0xdeadbeef;
352         hres = IPicture_get_Attributes (pic, &attr);
353         ok (hres == S_OK,"empty picture get attributes failed with hres 0x%08x\n", hres);
354         ok (attr == 0,"attr is %d, but should be 0\n", attr);
355
356         hres = IPicture_get_Handle (pic, &handle);
357         ok (hres == S_OK,"empty picture get handle failed with hres 0x%08x\n", hres);
358         ok (handle == 0, "empty picture get handle did not return 0, but 0x%08x\n", handle);
359         IPicture_Release (pic);
360 }
361
362 static void test_empty_image_2(void) {
363         LPBYTE          data;
364         LPSTREAM        stream;
365         IPicture*       pic = NULL;
366         HRESULT         hres;
367         LPVOID          pvObj = NULL;
368         HGLOBAL         hglob;
369         ULARGE_INTEGER  newpos1;
370         LARGE_INTEGER   seekto;
371         short           type;
372
373         /* Empty image at random stream position. */
374         hglob = GlobalAlloc (0, 200);
375         data = GlobalLock (hglob);
376         data += 42;
377         memcpy(data,"lt\0\0",4);
378         ((DWORD*)data)[1] = 0;
379         hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
380         ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
381
382         memset(&seekto,0,sizeof(seekto));
383         seekto.u.LowPart = 42;
384         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
385         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
386
387         pvObj = NULL;
388         hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
389         pic = pvObj;
390         ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
391         ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
392
393         hres = IPicture_get_Type (pic, &type);
394         ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
395         ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
396
397         IPicture_Release (pic);
398 }
399
400 static void test_Invoke(void)
401 {
402     IPictureDisp *picdisp;
403     HRESULT hr;
404     VARIANTARG vararg;
405     DISPPARAMS dispparams;
406     VARIANT varresult;
407     IStream *stream;
408     HGLOBAL hglob;
409     void *data;
410
411         hglob = GlobalAlloc (0, sizeof(gifimage));
412         data = GlobalLock(hglob);
413         memcpy(data, gifimage, sizeof(gifimage));
414     GlobalUnlock(hglob);
415
416         hr = CreateStreamOnHGlobal (hglob, FALSE, &stream);
417     ok_ole_success(hr, "CreateStreamOnHGlobal");
418
419         hr = pOleLoadPicture(stream, sizeof(gifimage), TRUE, &IID_IPictureDisp, (void **)&picdisp);
420     IStream_Release(stream);
421     ok_ole_success(hr, "OleLoadPicture");
422
423     V_VT(&vararg) = VT_BOOL;
424     V_BOOL(&vararg) = VARIANT_FALSE;
425     dispparams.cNamedArgs = 0;
426     dispparams.rgdispidNamedArgs = NULL;
427     dispparams.cArgs = 1;
428     dispparams.rgvarg = &vararg;
429     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IPictureDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
430     ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
431     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IUnknown, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
432     ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
433
434     dispparams.cArgs = 0;
435     dispparams.rgvarg = NULL;
436     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
437     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
438
439     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, NULL, NULL, NULL, NULL);
440     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
441
442     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, NULL, NULL, NULL);
443     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
444
445     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
446     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
447
448     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
449     ok_ole_success(hr, "IPictureDisp_Invoke");
450     ok(V_VT(&varresult) == VT_I4, "V_VT(&varresult) should have been VT_UINT instead of %d\n", V_VT(&varresult));
451
452     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
453     ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
454
455     hr = IPictureDisp_Invoke(picdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
456     ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
457
458     dispparams.cArgs = 1;
459     dispparams.rgvarg = &vararg;
460     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
461     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
462
463     dispparams.cArgs = 1;
464     dispparams.rgvarg = &vararg;
465     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
466     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
467
468     IPictureDisp_Release(picdisp);
469 }
470
471 static void test_OleCreatePictureIndirect(void)
472 {
473     IPicture *pict;
474     HRESULT hr;
475     short type;
476     OLE_HANDLE handle;
477
478     if(!pOleCreatePictureIndirect)
479     {
480         win_skip("Skipping OleCreatePictureIndirect tests\n");
481         return;
482     }
483
484     hr = pOleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
485     ok(hr == S_OK, "hr %08x\n", hr);
486
487     hr = IPicture_get_Type(pict, &type);
488     ok(hr == S_OK, "hr %08x\n", hr);
489     ok(type == PICTYPE_UNINITIALIZED, "type %d\n", type);
490
491     hr = IPicture_get_Handle(pict, &handle);
492     ok(hr == S_OK, "hr %08x\n", hr);
493     ok(handle == 0, "handle %08x\n", handle);
494
495     IPicture_Release(pict);
496 }
497
498 static void test_apm(void)
499 {
500     OLE_HANDLE handle;
501     LPSTREAM stream;
502     IPicture *pict;
503     HGLOBAL hglob;
504     LPBYTE *data;
505     LONG cxy;
506     BOOL keep;
507     short type;
508
509     hglob = GlobalAlloc (0, sizeof(apmdata));
510     data = GlobalLock(hglob);
511     memcpy(data, apmdata, sizeof(apmdata));
512
513     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
514     ole_check(OleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
515
516     ole_check(IPicture_get_Handle(pict, &handle));
517     ok(handle != 0, "handle is null\n");
518
519     ole_check(IPicture_get_Type(pict, &type));
520     expect_eq(type, PICTYPE_METAFILE, short, "%d");
521
522     ole_check(IPicture_get_Height(pict, &cxy));
523     expect_eq(cxy,  1667, LONG, "%d");
524
525     ole_check(IPicture_get_Width(pict, &cxy));
526     expect_eq(cxy,  1323, LONG, "%d");
527
528     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
529     todo_wine expect_eq(keep, FALSE, LONG, "%d");
530
531     ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
532     IPicture_Release(pict);
533     IStream_Release(stream);
534 }
535
536 static void test_metafile(void)
537 {
538     LPSTREAM stream;
539     IPicture *pict;
540     HGLOBAL hglob;
541     LPBYTE *data;
542
543     hglob = GlobalAlloc (0, sizeof(metafile));
544     data = GlobalLock(hglob);
545     memcpy(data, metafile, sizeof(metafile));
546
547     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
548     /* Windows does not load simple metafiles */
549     ole_expect(OleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
550
551     IStream_Release(stream);
552 }
553
554 static void test_enhmetafile(void)
555 {
556     OLE_HANDLE handle;
557     LPSTREAM stream;
558     IPicture *pict;
559     HGLOBAL hglob;
560     LPBYTE *data;
561     LONG cxy;
562     BOOL keep;
563     short type;
564
565     hglob = GlobalAlloc (0, sizeof(enhmetafile));
566     data = GlobalLock(hglob);
567     memcpy(data, enhmetafile, sizeof(enhmetafile));
568
569     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
570     ole_check(OleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
571
572     ole_check(IPicture_get_Handle(pict, &handle));
573     ok(handle != 0, "handle is null\n");
574
575     ole_check(IPicture_get_Type(pict, &type));
576     expect_eq(type, PICTYPE_ENHMETAFILE, short, "%d");
577
578     ole_check(IPicture_get_Height(pict, &cxy));
579     expect_eq(cxy, -23, LONG, "%d");
580
581     ole_check(IPicture_get_Width(pict, &cxy));
582     expect_eq(cxy, -25, LONG, "%d");
583
584     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
585     todo_wine expect_eq(keep, FALSE, LONG, "%d");
586
587     IPicture_Release(pict);
588     IStream_Release(stream);
589 }
590
591 static void test_Render(void)
592 {
593     IPicture *pic;
594     HRESULT hres;
595     short type;
596     PICTDESC desc;
597     HDC hdc = GetDC(0);
598
599     /* test IPicture::Render return code on uninitialized picture */
600     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
601     hres = IPicture_get_Type(pic, &type);
602     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
603     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
604     /* zero dimensions */
605     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
606     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
607     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
608     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
609     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
610     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
611     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
612     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
613     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
614     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
615     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
616     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
617     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
618     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
619     /* nonzero dimensions, PICTYPE_UNINITIALIZED */
620     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL);
621     ole_expect(hres, S_OK);
622     IPicture_Release(pic);
623
624     desc.cbSizeofstruct = sizeof(PICTDESC);
625     desc.picType = PICTYPE_ICON;
626     desc.u.icon.hicon = LoadIcon(NULL, IDI_APPLICATION);
627     if(!desc.u.icon.hicon){
628         win_skip("LoadIcon failed. Skipping...\n");
629         ReleaseDC(NULL, hdc);
630         return;
631     }
632
633     OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (VOID**)&pic);
634     /* zero dimensions, PICTYPE_ICON */
635     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
636     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
637     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
638     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
639     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
640     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
641     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
642     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
643     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
644     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
645     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
646     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
647     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
648     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
649     IPicture_Release(pic);
650
651     ReleaseDC(NULL, hdc);
652 }
653
654 static void test_get_Attributes(void)
655 {
656     IPicture *pic;
657     HRESULT hres;
658     short type;
659     DWORD attr;
660
661     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
662     hres = IPicture_get_Type(pic, &type);
663     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
664     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
665
666     hres = IPicture_get_Attributes(pic, NULL);
667     ole_expect(hres, E_POINTER);
668
669     attr = 0xdeadbeef;
670     hres = IPicture_get_Attributes(pic, &attr);
671     ole_expect(hres, S_OK);
672     ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %d\n", attr);
673
674     IPicture_Release(pic);
675 }
676
677 static void test_get_Handle(void)
678 {
679     IPicture *pic;
680     HRESULT hres;
681
682     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
683
684     hres = IPicture_get_Handle(pic, NULL);
685     ole_expect(hres, E_POINTER);
686
687     IPicture_Release(pic);
688 }
689
690 static void test_get_Type(void)
691 {
692     IPicture *pic;
693     HRESULT hres;
694
695     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
696
697     hres = IPicture_get_Type(pic, NULL);
698     ole_expect(hres, E_POINTER);
699
700     IPicture_Release(pic);
701 }
702
703 START_TEST(olepicture)
704 {
705         hOleaut32 = GetModuleHandleA("oleaut32.dll");
706         pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
707         pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect");
708         if (!pOleLoadPicture)
709         {
710             win_skip("OleLoadPicture is not available\n");
711             return;
712         }
713
714         /* Test regular 1x1 pixel images of gif, jpg, bmp type */
715         test_pic(gifimage, sizeof(gifimage));
716         test_pic(jpgimage, sizeof(jpgimage));
717         test_pic(bmpimage, sizeof(bmpimage));
718         test_pic(gif4pixel, sizeof(gif4pixel));
719         /* FIXME: No PNG support yet in Wine or in older Windows... */
720         if (0) test_pic(pngimage, sizeof(pngimage));
721         test_empty_image();
722         test_empty_image_2();
723         test_apm();
724         test_metafile();
725         test_enhmetafile();
726
727         test_Invoke();
728         test_OleCreatePictureIndirect();
729         test_Render();
730         test_get_Attributes();
731         test_get_Handle();
732         test_get_Type();
733 }
734
735
736 /* Helper functions only ... */
737
738
739 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
740 {
741   GlobalFree(This->supportHandle);
742   This->supportHandle=0;
743   HeapFree(GetProcessHeap(), 0, This);
744 }
745
746 static ULONG WINAPI NoStatStreamImpl_AddRef(
747                 IStream* iface)
748 {
749   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
750   return InterlockedIncrement(&This->ref);
751 }
752
753 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
754                   IStream*     iface,
755                   REFIID         riid,        /* [in] */
756                   void**         ppvObject)   /* [iid_is][out] */
757 {
758   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
759   if (ppvObject==0) return E_INVALIDARG;
760   *ppvObject = 0;
761   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
762   {
763     *ppvObject = This;
764   }
765   else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
766   {
767     *ppvObject = This;
768   }
769
770   if ((*ppvObject)==0)
771     return E_NOINTERFACE;
772   NoStatStreamImpl_AddRef(iface);
773   return S_OK;
774 }
775
776 static ULONG WINAPI NoStatStreamImpl_Release(
777                 IStream* iface)
778 {
779   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
780   ULONG newRef = InterlockedDecrement(&This->ref);
781   if (newRef==0)
782     NoStatStreamImpl_Destroy(This);
783   return newRef;
784 }
785
786 static HRESULT WINAPI NoStatStreamImpl_Read(
787                   IStream*     iface,
788                   void*          pv,        /* [length_is][size_is][out] */
789                   ULONG          cb,        /* [in] */
790                   ULONG*         pcbRead)   /* [out] */
791 {
792   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
793   void* supportBuffer;
794   ULONG bytesReadBuffer;
795   ULONG bytesToReadFromBuffer;
796
797   if (pcbRead==0)
798     pcbRead = &bytesReadBuffer;
799   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
800   supportBuffer = GlobalLock(This->supportHandle);
801   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
802   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
803   *pcbRead = bytesToReadFromBuffer;
804   GlobalUnlock(This->supportHandle);
805   if(*pcbRead == cb)
806     return S_OK;
807   return S_FALSE;
808 }
809
810 static HRESULT WINAPI NoStatStreamImpl_Write(
811                   IStream*     iface,
812                   const void*    pv,          /* [size_is][in] */
813                   ULONG          cb,          /* [in] */
814                   ULONG*         pcbWritten)  /* [out] */
815 {
816   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
817   void*          supportBuffer;
818   ULARGE_INTEGER newSize;
819   ULONG          bytesWritten = 0;
820
821   if (pcbWritten == 0)
822     pcbWritten = &bytesWritten;
823   if (cb == 0)
824     return S_OK;
825   newSize.u.HighPart = 0;
826   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
827   if (newSize.u.LowPart > This->streamSize.u.LowPart)
828    IStream_SetSize(iface, newSize);
829
830   supportBuffer = GlobalLock(This->supportHandle);
831   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
832   This->currentPosition.u.LowPart+=cb;
833   *pcbWritten = cb;
834   GlobalUnlock(This->supportHandle);
835   return S_OK;
836 }
837
838 static HRESULT WINAPI NoStatStreamImpl_Seek(
839                   IStream*      iface,
840                   LARGE_INTEGER   dlibMove,         /* [in] */
841                   DWORD           dwOrigin,         /* [in] */
842                   ULARGE_INTEGER* plibNewPosition) /* [out] */
843 {
844   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
845   ULARGE_INTEGER newPosition;
846   switch (dwOrigin)
847   {
848     case STREAM_SEEK_SET:
849       newPosition.u.HighPart = 0;
850       newPosition.u.LowPart = 0;
851       break;
852     case STREAM_SEEK_CUR:
853       newPosition = This->currentPosition;
854       break;
855     case STREAM_SEEK_END:
856       newPosition = This->streamSize;
857       break;
858     default:
859       return STG_E_INVALIDFUNCTION;
860   }
861   if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
862       return STG_E_INVALIDFUNCTION;
863   newPosition.QuadPart += dlibMove.QuadPart;
864   if (plibNewPosition) *plibNewPosition = newPosition;
865   This->currentPosition = newPosition;
866   return S_OK;
867 }
868
869 static HRESULT WINAPI NoStatStreamImpl_SetSize(
870                                      IStream*      iface,
871                                      ULARGE_INTEGER  libNewSize)   /* [in] */
872 {
873   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
874   HGLOBAL supportHandle;
875   if (libNewSize.u.HighPart != 0)
876     return STG_E_INVALIDFUNCTION;
877   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
878     return S_OK;
879   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
880   if (supportHandle == 0)
881     return STG_E_MEDIUMFULL;
882   This->supportHandle = supportHandle;
883   This->streamSize.u.LowPart = libNewSize.u.LowPart;
884   return S_OK;
885 }
886
887 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
888                                     IStream*      iface,
889                                     IStream*      pstm,         /* [unique][in] */
890                                     ULARGE_INTEGER  cb,           /* [in] */
891                                     ULARGE_INTEGER* pcbRead,      /* [out] */
892                                     ULARGE_INTEGER* pcbWritten)   /* [out] */
893 {
894   HRESULT        hr = S_OK;
895   BYTE           tmpBuffer[128];
896   ULONG          bytesRead, bytesWritten, copySize;
897   ULARGE_INTEGER totalBytesRead;
898   ULARGE_INTEGER totalBytesWritten;
899
900   if ( pstm == 0 )
901     return STG_E_INVALIDPOINTER;
902   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
903   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
904
905   while ( cb.u.LowPart > 0 )
906   {
907     if ( cb.u.LowPart >= 128 )
908       copySize = 128;
909     else
910       copySize = cb.u.LowPart;
911     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
912     totalBytesRead.u.LowPart += bytesRead;
913     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
914     totalBytesWritten.u.LowPart += bytesWritten;
915     if (bytesRead != bytesWritten)
916     {
917       hr = STG_E_MEDIUMFULL;
918       break;
919     }
920     if (bytesRead!=copySize)
921       cb.u.LowPart = 0;
922     else
923       cb.u.LowPart -= bytesRead;
924   }
925   if (pcbRead)
926   {
927     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
928     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
929   }
930
931   if (pcbWritten)
932   {
933     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
934     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
935   }
936   return hr;
937 }
938
939 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
940 {
941   return S_OK;
942 }
943 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
944
945 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
946                   IStream*       iface,
947                   ULARGE_INTEGER libOffset,   /* [in] */
948                   ULARGE_INTEGER cb,          /* [in] */
949                   DWORD          dwLockType)  /* [in] */
950 {
951   return S_OK;
952 }
953
954 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
955                   IStream*       iface,
956                   ULARGE_INTEGER libOffset,   /* [in] */
957                   ULARGE_INTEGER cb,          /* [in] */
958                   DWORD          dwLockType)  /* [in] */
959 {
960   return S_OK;
961 }
962
963 static HRESULT WINAPI NoStatStreamImpl_Stat(
964                   IStream*     iface,
965                   STATSTG*     pstatstg,     /* [out] */
966                   DWORD        grfStatFlag)  /* [in] */
967 {
968   return E_NOTIMPL;
969 }
970
971 static HRESULT WINAPI NoStatStreamImpl_Clone(
972                   IStream*     iface,
973                   IStream**    ppstm) /* [out] */
974 {
975   return E_NOTIMPL;
976 }
977 static const IStreamVtbl NoStatStreamImpl_Vtbl;
978
979 /*
980     Build an object that implements IStream, without IStream_Stat capabilities.
981     Receives a memory handle with data buffer. If memory handle is non-null,
982     it is assumed to be unlocked, otherwise an internal memory handle is allocated.
983     In any case the object takes ownership of memory handle and will free it on
984     object release.
985  */
986 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
987 {
988   NoStatStreamImpl* newStream;
989
990   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
991   if (newStream!=0)
992   {
993     newStream->lpVtbl = &NoStatStreamImpl_Vtbl;
994     newStream->ref    = 1;
995     newStream->supportHandle = hGlobal;
996
997     if (!newStream->supportHandle)
998       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
999                                              GMEM_SHARE, 0);
1000     newStream->currentPosition.u.HighPart = 0;
1001     newStream->currentPosition.u.LowPart = 0;
1002     newStream->streamSize.u.HighPart = 0;
1003     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
1004   }
1005   return newStream;
1006 }
1007
1008
1009 static const IStreamVtbl NoStatStreamImpl_Vtbl =
1010 {
1011     NoStatStreamImpl_QueryInterface,
1012     NoStatStreamImpl_AddRef,
1013     NoStatStreamImpl_Release,
1014     NoStatStreamImpl_Read,
1015     NoStatStreamImpl_Write,
1016     NoStatStreamImpl_Seek,
1017     NoStatStreamImpl_SetSize,
1018     NoStatStreamImpl_CopyTo,
1019     NoStatStreamImpl_Commit,
1020     NoStatStreamImpl_Revert,
1021     NoStatStreamImpl_LockRegion,
1022     NoStatStreamImpl_UnlockRegion,
1023     NoStatStreamImpl_Stat,
1024     NoStatStreamImpl_Clone
1025 };