user32: Use the stored color and mask bitmaps instead of the raw bits in GetIconInfo.
[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         IStream_Release (stream);
361 }
362
363 static void test_empty_image_2(void) {
364         LPBYTE          data;
365         LPSTREAM        stream;
366         IPicture*       pic = NULL;
367         HRESULT         hres;
368         LPVOID          pvObj = NULL;
369         HGLOBAL         hglob;
370         ULARGE_INTEGER  newpos1;
371         LARGE_INTEGER   seekto;
372         short           type;
373
374         /* Empty image at random stream position. */
375         hglob = GlobalAlloc (0, 200);
376         data = GlobalLock (hglob);
377         data += 42;
378         memcpy(data,"lt\0\0",4);
379         ((DWORD*)data)[1] = 0;
380         hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
381         ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
382
383         memset(&seekto,0,sizeof(seekto));
384         seekto.u.LowPart = 42;
385         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
386         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
387
388         pvObj = NULL;
389         hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
390         pic = pvObj;
391         ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
392         ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
393
394         hres = IPicture_get_Type (pic, &type);
395         ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
396         ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
397
398         IPicture_Release (pic);
399         IStream_Release (stream);
400 }
401
402 static void test_Invoke(void)
403 {
404     IPictureDisp *picdisp;
405     HRESULT hr;
406     VARIANTARG vararg;
407     DISPPARAMS dispparams;
408     VARIANT varresult;
409     IStream *stream;
410     HGLOBAL hglob;
411     void *data;
412
413     hglob = GlobalAlloc (0, sizeof(gifimage));
414     data = GlobalLock(hglob);
415     memcpy(data, gifimage, sizeof(gifimage));
416     GlobalUnlock(hglob);
417
418     hr = CreateStreamOnHGlobal (hglob, FALSE, &stream);
419     ok_ole_success(hr, "CreateStreamOnHGlobal");
420
421     hr = pOleLoadPicture(stream, sizeof(gifimage), TRUE, &IID_IPictureDisp, (void **)&picdisp);
422     IStream_Release(stream);
423     GlobalFree(hglob);
424     ok_ole_success(hr, "OleLoadPicture");
425
426     V_VT(&vararg) = VT_BOOL;
427     V_BOOL(&vararg) = VARIANT_FALSE;
428     dispparams.cNamedArgs = 0;
429     dispparams.rgdispidNamedArgs = NULL;
430     dispparams.cArgs = 1;
431     dispparams.rgvarg = &vararg;
432     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IPictureDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
433     ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
434     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IUnknown, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
435     ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
436
437     dispparams.cArgs = 0;
438     dispparams.rgvarg = NULL;
439     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
440     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
441
442     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, 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, NULL, 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, NULL, &varresult, NULL, NULL);
449     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
450
451     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
452     ok_ole_success(hr, "IPictureDisp_Invoke");
453     ok(V_VT(&varresult) == VT_I4, "V_VT(&varresult) should have been VT_UINT instead of %d\n", V_VT(&varresult));
454
455     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_METHOD, &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     hr = IPictureDisp_Invoke(picdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
459     ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
460
461     dispparams.cArgs = 1;
462     dispparams.rgvarg = &vararg;
463     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
464     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
465
466     dispparams.cArgs = 1;
467     dispparams.rgvarg = &vararg;
468     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
469     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
470
471     IPictureDisp_Release(picdisp);
472 }
473
474 static void test_OleCreatePictureIndirect(void)
475 {
476     IPicture *pict;
477     HRESULT hr;
478     short type;
479     OLE_HANDLE handle;
480
481     if(!pOleCreatePictureIndirect)
482     {
483         win_skip("Skipping OleCreatePictureIndirect tests\n");
484         return;
485     }
486
487     hr = pOleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
488     ok(hr == S_OK, "hr %08x\n", hr);
489
490     hr = IPicture_get_Type(pict, &type);
491     ok(hr == S_OK, "hr %08x\n", hr);
492     ok(type == PICTYPE_UNINITIALIZED, "type %d\n", type);
493
494     hr = IPicture_get_Handle(pict, &handle);
495     ok(hr == S_OK, "hr %08x\n", hr);
496     ok(handle == 0, "handle %08x\n", handle);
497
498     IPicture_Release(pict);
499 }
500
501 static void test_apm(void)
502 {
503     OLE_HANDLE handle;
504     LPSTREAM stream;
505     IPicture *pict;
506     HGLOBAL hglob;
507     LPBYTE *data;
508     LONG cxy;
509     BOOL keep;
510     short type;
511
512     hglob = GlobalAlloc (0, sizeof(apmdata));
513     data = GlobalLock(hglob);
514     memcpy(data, apmdata, sizeof(apmdata));
515
516     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
517     ole_check(OleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
518
519     ole_check(IPicture_get_Handle(pict, &handle));
520     ok(handle != 0, "handle is null\n");
521
522     ole_check(IPicture_get_Type(pict, &type));
523     expect_eq(type, PICTYPE_METAFILE, short, "%d");
524
525     ole_check(IPicture_get_Height(pict, &cxy));
526     expect_eq(cxy,  1667, LONG, "%d");
527
528     ole_check(IPicture_get_Width(pict, &cxy));
529     expect_eq(cxy,  1323, LONG, "%d");
530
531     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
532     todo_wine expect_eq(keep, FALSE, LONG, "%d");
533
534     ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
535     IPicture_Release(pict);
536     IStream_Release(stream);
537 }
538
539 static void test_metafile(void)
540 {
541     LPSTREAM stream;
542     IPicture *pict;
543     HGLOBAL hglob;
544     LPBYTE *data;
545
546     hglob = GlobalAlloc (0, sizeof(metafile));
547     data = GlobalLock(hglob);
548     memcpy(data, metafile, sizeof(metafile));
549
550     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
551     /* Windows does not load simple metafiles */
552     ole_expect(OleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
553
554     IStream_Release(stream);
555 }
556
557 static void test_enhmetafile(void)
558 {
559     OLE_HANDLE handle;
560     LPSTREAM stream;
561     IPicture *pict;
562     HGLOBAL hglob;
563     LPBYTE *data;
564     LONG cxy;
565     BOOL keep;
566     short type;
567
568     hglob = GlobalAlloc (0, sizeof(enhmetafile));
569     data = GlobalLock(hglob);
570     memcpy(data, enhmetafile, sizeof(enhmetafile));
571
572     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
573     ole_check(OleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
574
575     ole_check(IPicture_get_Handle(pict, &handle));
576     ok(handle != 0, "handle is null\n");
577
578     ole_check(IPicture_get_Type(pict, &type));
579     expect_eq(type, PICTYPE_ENHMETAFILE, short, "%d");
580
581     ole_check(IPicture_get_Height(pict, &cxy));
582     expect_eq(cxy, -23, LONG, "%d");
583
584     ole_check(IPicture_get_Width(pict, &cxy));
585     expect_eq(cxy, -25, LONG, "%d");
586
587     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
588     todo_wine expect_eq(keep, FALSE, LONG, "%d");
589
590     IPicture_Release(pict);
591     IStream_Release(stream);
592 }
593
594 static void test_Render(void)
595 {
596     IPicture *pic;
597     HRESULT hres;
598     short type;
599     PICTDESC desc;
600     OLE_XSIZE_HIMETRIC pWidth;
601     OLE_YSIZE_HIMETRIC pHeight;
602     COLORREF result, expected;
603     HDC hdc = GetDC(0);
604
605     /* test IPicture::Render return code on uninitialized picture */
606     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
607     hres = IPicture_get_Type(pic, &type);
608     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
609     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
610     /* zero dimensions */
611     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
612     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
613     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
614     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
615     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
616     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
617     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
618     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
619     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
620     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
621     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
622     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
623     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
624     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
625     /* nonzero dimensions, PICTYPE_UNINITIALIZED */
626     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL);
627     ole_expect(hres, S_OK);
628     IPicture_Release(pic);
629
630     desc.cbSizeofstruct = sizeof(PICTDESC);
631     desc.picType = PICTYPE_ICON;
632     desc.u.icon.hicon = LoadIcon(NULL, IDI_APPLICATION);
633     if(!desc.u.icon.hicon){
634         win_skip("LoadIcon failed. Skipping...\n");
635         ReleaseDC(NULL, hdc);
636         return;
637     }
638
639     OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (VOID**)&pic);
640     /* zero dimensions, PICTYPE_ICON */
641     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
642     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
643     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
644     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
645     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
646     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
647     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
648     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
649     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
650     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
651     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
652     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
653     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
654     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
655
656     /* Check if target size and position is respected */
657     IPicture_get_Width(pic, &pWidth);
658     IPicture_get_Height(pic, &pHeight);
659
660     SetPixelV(hdc, 0, 0, 0x00F0F0F0);
661     SetPixelV(hdc, 5, 5, 0x00F0F0F0);
662     SetPixelV(hdc, 10, 10, 0x00F0F0F0);
663     expected = GetPixel(hdc, 0, 0);
664
665     hres = IPicture_Render(pic, hdc, 1, 1, 9, 9, 0, 0, pWidth, -pHeight, NULL);
666     ole_expect(hres, S_OK);
667
668     if(hres != S_OK) {
669         IPicture_Release(pic);
670         ReleaseDC(NULL, hdc);
671         return;
672     }
673
674     /* Evaluate the rendered Icon */
675     result = GetPixel(hdc, 0, 0);
676     ok(result == expected,
677        "Color at 0,0 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
678     result = GetPixel(hdc, 5, 5);
679     ok(result != expected ||
680         broken(result == expected), /* WinNT 4.0 and older may claim they drew */
681                                     /* the icon, even if they didn't. */
682        "Color at 5,5 should have changed, but still was 0x%06X\n", expected);
683     result = GetPixel(hdc, 10, 10);
684     ok(result == expected,
685        "Color at 10,10 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
686
687     IPicture_Release(pic);
688     ReleaseDC(NULL, hdc);
689 }
690
691 static void test_get_Attributes(void)
692 {
693     IPicture *pic;
694     HRESULT hres;
695     short type;
696     DWORD attr;
697
698     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
699     hres = IPicture_get_Type(pic, &type);
700     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
701     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
702
703     hres = IPicture_get_Attributes(pic, NULL);
704     ole_expect(hres, E_POINTER);
705
706     attr = 0xdeadbeef;
707     hres = IPicture_get_Attributes(pic, &attr);
708     ole_expect(hres, S_OK);
709     ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %d\n", attr);
710
711     IPicture_Release(pic);
712 }
713
714 static void test_get_Handle(void)
715 {
716     IPicture *pic;
717     HRESULT hres;
718
719     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
720
721     hres = IPicture_get_Handle(pic, NULL);
722     ole_expect(hres, E_POINTER);
723
724     IPicture_Release(pic);
725 }
726
727 static void test_get_Type(void)
728 {
729     IPicture *pic;
730     HRESULT hres;
731
732     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
733
734     hres = IPicture_get_Type(pic, NULL);
735     ole_expect(hres, E_POINTER);
736
737     IPicture_Release(pic);
738 }
739
740 START_TEST(olepicture)
741 {
742         hOleaut32 = GetModuleHandleA("oleaut32.dll");
743         pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
744         pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect");
745         if (!pOleLoadPicture)
746         {
747             win_skip("OleLoadPicture is not available\n");
748             return;
749         }
750
751         /* Test regular 1x1 pixel images of gif, jpg, bmp type */
752         test_pic(gifimage, sizeof(gifimage));
753         test_pic(jpgimage, sizeof(jpgimage));
754         test_pic(bmpimage, sizeof(bmpimage));
755         test_pic(gif4pixel, sizeof(gif4pixel));
756         /* FIXME: No PNG support yet in Wine or in older Windows... */
757         if (0) test_pic(pngimage, sizeof(pngimage));
758         test_empty_image();
759         test_empty_image_2();
760         test_apm();
761         test_metafile();
762         test_enhmetafile();
763
764         test_Invoke();
765         test_OleCreatePictureIndirect();
766         test_Render();
767         test_get_Attributes();
768         test_get_Handle();
769         test_get_Type();
770 }
771
772
773 /* Helper functions only ... */
774
775
776 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
777 {
778   GlobalFree(This->supportHandle);
779   This->supportHandle=0;
780   HeapFree(GetProcessHeap(), 0, This);
781 }
782
783 static ULONG WINAPI NoStatStreamImpl_AddRef(
784                 IStream* iface)
785 {
786   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
787   return InterlockedIncrement(&This->ref);
788 }
789
790 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
791                   IStream*     iface,
792                   REFIID         riid,        /* [in] */
793                   void**         ppvObject)   /* [iid_is][out] */
794 {
795   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
796   if (ppvObject==0) return E_INVALIDARG;
797   *ppvObject = 0;
798   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
799   {
800     *ppvObject = This;
801   }
802   else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
803   {
804     *ppvObject = This;
805   }
806
807   if ((*ppvObject)==0)
808     return E_NOINTERFACE;
809   NoStatStreamImpl_AddRef(iface);
810   return S_OK;
811 }
812
813 static ULONG WINAPI NoStatStreamImpl_Release(
814                 IStream* iface)
815 {
816   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
817   ULONG newRef = InterlockedDecrement(&This->ref);
818   if (newRef==0)
819     NoStatStreamImpl_Destroy(This);
820   return newRef;
821 }
822
823 static HRESULT WINAPI NoStatStreamImpl_Read(
824                   IStream*     iface,
825                   void*          pv,        /* [length_is][size_is][out] */
826                   ULONG          cb,        /* [in] */
827                   ULONG*         pcbRead)   /* [out] */
828 {
829   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
830   void* supportBuffer;
831   ULONG bytesReadBuffer;
832   ULONG bytesToReadFromBuffer;
833
834   if (pcbRead==0)
835     pcbRead = &bytesReadBuffer;
836   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
837   supportBuffer = GlobalLock(This->supportHandle);
838   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
839   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
840   *pcbRead = bytesToReadFromBuffer;
841   GlobalUnlock(This->supportHandle);
842   if(*pcbRead == cb)
843     return S_OK;
844   return S_FALSE;
845 }
846
847 static HRESULT WINAPI NoStatStreamImpl_Write(
848                   IStream*     iface,
849                   const void*    pv,          /* [size_is][in] */
850                   ULONG          cb,          /* [in] */
851                   ULONG*         pcbWritten)  /* [out] */
852 {
853   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
854   void*          supportBuffer;
855   ULARGE_INTEGER newSize;
856   ULONG          bytesWritten = 0;
857
858   if (pcbWritten == 0)
859     pcbWritten = &bytesWritten;
860   if (cb == 0)
861     return S_OK;
862   newSize.u.HighPart = 0;
863   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
864   if (newSize.u.LowPart > This->streamSize.u.LowPart)
865    IStream_SetSize(iface, newSize);
866
867   supportBuffer = GlobalLock(This->supportHandle);
868   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
869   This->currentPosition.u.LowPart+=cb;
870   *pcbWritten = cb;
871   GlobalUnlock(This->supportHandle);
872   return S_OK;
873 }
874
875 static HRESULT WINAPI NoStatStreamImpl_Seek(
876                   IStream*      iface,
877                   LARGE_INTEGER   dlibMove,         /* [in] */
878                   DWORD           dwOrigin,         /* [in] */
879                   ULARGE_INTEGER* plibNewPosition) /* [out] */
880 {
881   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
882   ULARGE_INTEGER newPosition;
883   switch (dwOrigin)
884   {
885     case STREAM_SEEK_SET:
886       newPosition.u.HighPart = 0;
887       newPosition.u.LowPart = 0;
888       break;
889     case STREAM_SEEK_CUR:
890       newPosition = This->currentPosition;
891       break;
892     case STREAM_SEEK_END:
893       newPosition = This->streamSize;
894       break;
895     default:
896       return STG_E_INVALIDFUNCTION;
897   }
898   if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
899       return STG_E_INVALIDFUNCTION;
900   newPosition.QuadPart += dlibMove.QuadPart;
901   if (plibNewPosition) *plibNewPosition = newPosition;
902   This->currentPosition = newPosition;
903   return S_OK;
904 }
905
906 static HRESULT WINAPI NoStatStreamImpl_SetSize(
907                                      IStream*      iface,
908                                      ULARGE_INTEGER  libNewSize)   /* [in] */
909 {
910   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
911   HGLOBAL supportHandle;
912   if (libNewSize.u.HighPart != 0)
913     return STG_E_INVALIDFUNCTION;
914   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
915     return S_OK;
916   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
917   if (supportHandle == 0)
918     return STG_E_MEDIUMFULL;
919   This->supportHandle = supportHandle;
920   This->streamSize.u.LowPart = libNewSize.u.LowPart;
921   return S_OK;
922 }
923
924 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
925                                     IStream*      iface,
926                                     IStream*      pstm,         /* [unique][in] */
927                                     ULARGE_INTEGER  cb,           /* [in] */
928                                     ULARGE_INTEGER* pcbRead,      /* [out] */
929                                     ULARGE_INTEGER* pcbWritten)   /* [out] */
930 {
931   HRESULT        hr = S_OK;
932   BYTE           tmpBuffer[128];
933   ULONG          bytesRead, bytesWritten, copySize;
934   ULARGE_INTEGER totalBytesRead;
935   ULARGE_INTEGER totalBytesWritten;
936
937   if ( pstm == 0 )
938     return STG_E_INVALIDPOINTER;
939   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
940   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
941
942   while ( cb.u.LowPart > 0 )
943   {
944     if ( cb.u.LowPart >= 128 )
945       copySize = 128;
946     else
947       copySize = cb.u.LowPart;
948     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
949     totalBytesRead.u.LowPart += bytesRead;
950     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
951     totalBytesWritten.u.LowPart += bytesWritten;
952     if (bytesRead != bytesWritten)
953     {
954       hr = STG_E_MEDIUMFULL;
955       break;
956     }
957     if (bytesRead!=copySize)
958       cb.u.LowPart = 0;
959     else
960       cb.u.LowPart -= bytesRead;
961   }
962   if (pcbRead)
963   {
964     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
965     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
966   }
967
968   if (pcbWritten)
969   {
970     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
971     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
972   }
973   return hr;
974 }
975
976 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
977 {
978   return S_OK;
979 }
980 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
981
982 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
983                   IStream*       iface,
984                   ULARGE_INTEGER libOffset,   /* [in] */
985                   ULARGE_INTEGER cb,          /* [in] */
986                   DWORD          dwLockType)  /* [in] */
987 {
988   return S_OK;
989 }
990
991 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
992                   IStream*       iface,
993                   ULARGE_INTEGER libOffset,   /* [in] */
994                   ULARGE_INTEGER cb,          /* [in] */
995                   DWORD          dwLockType)  /* [in] */
996 {
997   return S_OK;
998 }
999
1000 static HRESULT WINAPI NoStatStreamImpl_Stat(
1001                   IStream*     iface,
1002                   STATSTG*     pstatstg,     /* [out] */
1003                   DWORD        grfStatFlag)  /* [in] */
1004 {
1005   return E_NOTIMPL;
1006 }
1007
1008 static HRESULT WINAPI NoStatStreamImpl_Clone(
1009                   IStream*     iface,
1010                   IStream**    ppstm) /* [out] */
1011 {
1012   return E_NOTIMPL;
1013 }
1014 static const IStreamVtbl NoStatStreamImpl_Vtbl;
1015
1016 /*
1017     Build an object that implements IStream, without IStream_Stat capabilities.
1018     Receives a memory handle with data buffer. If memory handle is non-null,
1019     it is assumed to be unlocked, otherwise an internal memory handle is allocated.
1020     In any case the object takes ownership of memory handle and will free it on
1021     object release.
1022  */
1023 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
1024 {
1025   NoStatStreamImpl* newStream;
1026
1027   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
1028   if (newStream!=0)
1029   {
1030     newStream->lpVtbl = &NoStatStreamImpl_Vtbl;
1031     newStream->ref    = 1;
1032     newStream->supportHandle = hGlobal;
1033
1034     if (!newStream->supportHandle)
1035       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
1036                                              GMEM_SHARE, 0);
1037     newStream->currentPosition.u.HighPart = 0;
1038     newStream->currentPosition.u.LowPart = 0;
1039     newStream->streamSize.u.HighPart = 0;
1040     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
1041   }
1042   return newStream;
1043 }
1044
1045
1046 static const IStreamVtbl NoStatStreamImpl_Vtbl =
1047 {
1048     NoStatStreamImpl_QueryInterface,
1049     NoStatStreamImpl_AddRef,
1050     NoStatStreamImpl_Release,
1051     NoStatStreamImpl_Read,
1052     NoStatStreamImpl_Write,
1053     NoStatStreamImpl_Seek,
1054     NoStatStreamImpl_SetSize,
1055     NoStatStreamImpl_CopyTo,
1056     NoStatStreamImpl_Commit,
1057     NoStatStreamImpl_Revert,
1058     NoStatStreamImpl_LockRegion,
1059     NoStatStreamImpl_UnlockRegion,
1060     NoStatStreamImpl_Stat,
1061     NoStatStreamImpl_Clone
1062 };