usrmarshal: Add a test for marshalling a SAFEARRAY of VT_BSTR.
[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     OLE_XSIZE_HIMETRIC pWidth;
598     OLE_YSIZE_HIMETRIC pHeight;
599     COLORREF result, expected;
600     HDC hdc = GetDC(0);
601
602     /* test IPicture::Render return code on uninitialized picture */
603     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
604     hres = IPicture_get_Type(pic, &type);
605     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
606     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
607     /* zero dimensions */
608     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
609     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
610     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
611     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
612     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
613     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
614     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
615     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
616     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
617     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
618     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
619     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
620     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
621     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
622     /* nonzero dimensions, PICTYPE_UNINITIALIZED */
623     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL);
624     ole_expect(hres, S_OK);
625     IPicture_Release(pic);
626
627     desc.cbSizeofstruct = sizeof(PICTDESC);
628     desc.picType = PICTYPE_ICON;
629     desc.u.icon.hicon = LoadIcon(NULL, IDI_APPLICATION);
630     if(!desc.u.icon.hicon){
631         win_skip("LoadIcon failed. Skipping...\n");
632         ReleaseDC(NULL, hdc);
633         return;
634     }
635
636     OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (VOID**)&pic);
637     /* zero dimensions, PICTYPE_ICON */
638     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
639     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
640     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
641     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
642     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
643     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
644     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
645     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
646     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
647     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
648     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
649     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
650     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
651     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
652
653     /* Check if target size and position is respected */
654     IPicture_get_Width(pic, &pWidth);
655     IPicture_get_Height(pic, &pHeight);
656
657     SetPixelV(hdc, 0, 0, 0x00F0F0F0);
658     SetPixelV(hdc, 5, 5, 0x00F0F0F0);
659     SetPixelV(hdc, 10, 10, 0x00F0F0F0);
660     expected = GetPixel(hdc, 0, 0);
661
662     hres = IPicture_Render(pic, hdc, 1, 1, 9, 9, 0, 0, pWidth, -pHeight, NULL);
663     ole_expect(hres, S_OK);
664
665     if(hres != S_OK) {
666         IPicture_Release(pic);
667         ReleaseDC(NULL, hdc);
668         return;
669     }
670
671     /* Evaluate the rendered Icon */
672     result = GetPixel(hdc, 0, 0);
673     ok(result == expected,
674        "Color at 0,0 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
675     result = GetPixel(hdc, 5, 5);
676     ok(result != expected ||
677         broken(result == expected), /* WinNT 4.0 and older may claim they drew */
678                                     /* the icon, even if they didn't. */
679        "Color at 5,5 should have changed, but still was 0x%06X\n", expected);
680     result = GetPixel(hdc, 10, 10);
681     ok(result == expected,
682        "Color at 10,10 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
683
684     IPicture_Release(pic);
685     ReleaseDC(NULL, hdc);
686 }
687
688 static void test_get_Attributes(void)
689 {
690     IPicture *pic;
691     HRESULT hres;
692     short type;
693     DWORD attr;
694
695     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
696     hres = IPicture_get_Type(pic, &type);
697     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
698     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
699
700     hres = IPicture_get_Attributes(pic, NULL);
701     ole_expect(hres, E_POINTER);
702
703     attr = 0xdeadbeef;
704     hres = IPicture_get_Attributes(pic, &attr);
705     ole_expect(hres, S_OK);
706     ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %d\n", attr);
707
708     IPicture_Release(pic);
709 }
710
711 static void test_get_Handle(void)
712 {
713     IPicture *pic;
714     HRESULT hres;
715
716     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
717
718     hres = IPicture_get_Handle(pic, NULL);
719     ole_expect(hres, E_POINTER);
720
721     IPicture_Release(pic);
722 }
723
724 static void test_get_Type(void)
725 {
726     IPicture *pic;
727     HRESULT hres;
728
729     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
730
731     hres = IPicture_get_Type(pic, NULL);
732     ole_expect(hres, E_POINTER);
733
734     IPicture_Release(pic);
735 }
736
737 START_TEST(olepicture)
738 {
739         hOleaut32 = GetModuleHandleA("oleaut32.dll");
740         pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
741         pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect");
742         if (!pOleLoadPicture)
743         {
744             win_skip("OleLoadPicture is not available\n");
745             return;
746         }
747
748         /* Test regular 1x1 pixel images of gif, jpg, bmp type */
749         test_pic(gifimage, sizeof(gifimage));
750         test_pic(jpgimage, sizeof(jpgimage));
751         test_pic(bmpimage, sizeof(bmpimage));
752         test_pic(gif4pixel, sizeof(gif4pixel));
753         /* FIXME: No PNG support yet in Wine or in older Windows... */
754         if (0) test_pic(pngimage, sizeof(pngimage));
755         test_empty_image();
756         test_empty_image_2();
757         test_apm();
758         test_metafile();
759         test_enhmetafile();
760
761         test_Invoke();
762         test_OleCreatePictureIndirect();
763         test_Render();
764         test_get_Attributes();
765         test_get_Handle();
766         test_get_Type();
767 }
768
769
770 /* Helper functions only ... */
771
772
773 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
774 {
775   GlobalFree(This->supportHandle);
776   This->supportHandle=0;
777   HeapFree(GetProcessHeap(), 0, This);
778 }
779
780 static ULONG WINAPI NoStatStreamImpl_AddRef(
781                 IStream* iface)
782 {
783   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
784   return InterlockedIncrement(&This->ref);
785 }
786
787 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
788                   IStream*     iface,
789                   REFIID         riid,        /* [in] */
790                   void**         ppvObject)   /* [iid_is][out] */
791 {
792   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
793   if (ppvObject==0) return E_INVALIDARG;
794   *ppvObject = 0;
795   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
796   {
797     *ppvObject = This;
798   }
799   else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
800   {
801     *ppvObject = This;
802   }
803
804   if ((*ppvObject)==0)
805     return E_NOINTERFACE;
806   NoStatStreamImpl_AddRef(iface);
807   return S_OK;
808 }
809
810 static ULONG WINAPI NoStatStreamImpl_Release(
811                 IStream* iface)
812 {
813   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
814   ULONG newRef = InterlockedDecrement(&This->ref);
815   if (newRef==0)
816     NoStatStreamImpl_Destroy(This);
817   return newRef;
818 }
819
820 static HRESULT WINAPI NoStatStreamImpl_Read(
821                   IStream*     iface,
822                   void*          pv,        /* [length_is][size_is][out] */
823                   ULONG          cb,        /* [in] */
824                   ULONG*         pcbRead)   /* [out] */
825 {
826   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
827   void* supportBuffer;
828   ULONG bytesReadBuffer;
829   ULONG bytesToReadFromBuffer;
830
831   if (pcbRead==0)
832     pcbRead = &bytesReadBuffer;
833   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
834   supportBuffer = GlobalLock(This->supportHandle);
835   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
836   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
837   *pcbRead = bytesToReadFromBuffer;
838   GlobalUnlock(This->supportHandle);
839   if(*pcbRead == cb)
840     return S_OK;
841   return S_FALSE;
842 }
843
844 static HRESULT WINAPI NoStatStreamImpl_Write(
845                   IStream*     iface,
846                   const void*    pv,          /* [size_is][in] */
847                   ULONG          cb,          /* [in] */
848                   ULONG*         pcbWritten)  /* [out] */
849 {
850   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
851   void*          supportBuffer;
852   ULARGE_INTEGER newSize;
853   ULONG          bytesWritten = 0;
854
855   if (pcbWritten == 0)
856     pcbWritten = &bytesWritten;
857   if (cb == 0)
858     return S_OK;
859   newSize.u.HighPart = 0;
860   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
861   if (newSize.u.LowPart > This->streamSize.u.LowPart)
862    IStream_SetSize(iface, newSize);
863
864   supportBuffer = GlobalLock(This->supportHandle);
865   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
866   This->currentPosition.u.LowPart+=cb;
867   *pcbWritten = cb;
868   GlobalUnlock(This->supportHandle);
869   return S_OK;
870 }
871
872 static HRESULT WINAPI NoStatStreamImpl_Seek(
873                   IStream*      iface,
874                   LARGE_INTEGER   dlibMove,         /* [in] */
875                   DWORD           dwOrigin,         /* [in] */
876                   ULARGE_INTEGER* plibNewPosition) /* [out] */
877 {
878   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
879   ULARGE_INTEGER newPosition;
880   switch (dwOrigin)
881   {
882     case STREAM_SEEK_SET:
883       newPosition.u.HighPart = 0;
884       newPosition.u.LowPart = 0;
885       break;
886     case STREAM_SEEK_CUR:
887       newPosition = This->currentPosition;
888       break;
889     case STREAM_SEEK_END:
890       newPosition = This->streamSize;
891       break;
892     default:
893       return STG_E_INVALIDFUNCTION;
894   }
895   if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
896       return STG_E_INVALIDFUNCTION;
897   newPosition.QuadPart += dlibMove.QuadPart;
898   if (plibNewPosition) *plibNewPosition = newPosition;
899   This->currentPosition = newPosition;
900   return S_OK;
901 }
902
903 static HRESULT WINAPI NoStatStreamImpl_SetSize(
904                                      IStream*      iface,
905                                      ULARGE_INTEGER  libNewSize)   /* [in] */
906 {
907   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
908   HGLOBAL supportHandle;
909   if (libNewSize.u.HighPart != 0)
910     return STG_E_INVALIDFUNCTION;
911   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
912     return S_OK;
913   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
914   if (supportHandle == 0)
915     return STG_E_MEDIUMFULL;
916   This->supportHandle = supportHandle;
917   This->streamSize.u.LowPart = libNewSize.u.LowPart;
918   return S_OK;
919 }
920
921 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
922                                     IStream*      iface,
923                                     IStream*      pstm,         /* [unique][in] */
924                                     ULARGE_INTEGER  cb,           /* [in] */
925                                     ULARGE_INTEGER* pcbRead,      /* [out] */
926                                     ULARGE_INTEGER* pcbWritten)   /* [out] */
927 {
928   HRESULT        hr = S_OK;
929   BYTE           tmpBuffer[128];
930   ULONG          bytesRead, bytesWritten, copySize;
931   ULARGE_INTEGER totalBytesRead;
932   ULARGE_INTEGER totalBytesWritten;
933
934   if ( pstm == 0 )
935     return STG_E_INVALIDPOINTER;
936   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
937   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
938
939   while ( cb.u.LowPart > 0 )
940   {
941     if ( cb.u.LowPart >= 128 )
942       copySize = 128;
943     else
944       copySize = cb.u.LowPart;
945     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
946     totalBytesRead.u.LowPart += bytesRead;
947     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
948     totalBytesWritten.u.LowPart += bytesWritten;
949     if (bytesRead != bytesWritten)
950     {
951       hr = STG_E_MEDIUMFULL;
952       break;
953     }
954     if (bytesRead!=copySize)
955       cb.u.LowPart = 0;
956     else
957       cb.u.LowPart -= bytesRead;
958   }
959   if (pcbRead)
960   {
961     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
962     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
963   }
964
965   if (pcbWritten)
966   {
967     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
968     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
969   }
970   return hr;
971 }
972
973 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
974 {
975   return S_OK;
976 }
977 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
978
979 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
980                   IStream*       iface,
981                   ULARGE_INTEGER libOffset,   /* [in] */
982                   ULARGE_INTEGER cb,          /* [in] */
983                   DWORD          dwLockType)  /* [in] */
984 {
985   return S_OK;
986 }
987
988 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
989                   IStream*       iface,
990                   ULARGE_INTEGER libOffset,   /* [in] */
991                   ULARGE_INTEGER cb,          /* [in] */
992                   DWORD          dwLockType)  /* [in] */
993 {
994   return S_OK;
995 }
996
997 static HRESULT WINAPI NoStatStreamImpl_Stat(
998                   IStream*     iface,
999                   STATSTG*     pstatstg,     /* [out] */
1000                   DWORD        grfStatFlag)  /* [in] */
1001 {
1002   return E_NOTIMPL;
1003 }
1004
1005 static HRESULT WINAPI NoStatStreamImpl_Clone(
1006                   IStream*     iface,
1007                   IStream**    ppstm) /* [out] */
1008 {
1009   return E_NOTIMPL;
1010 }
1011 static const IStreamVtbl NoStatStreamImpl_Vtbl;
1012
1013 /*
1014     Build an object that implements IStream, without IStream_Stat capabilities.
1015     Receives a memory handle with data buffer. If memory handle is non-null,
1016     it is assumed to be unlocked, otherwise an internal memory handle is allocated.
1017     In any case the object takes ownership of memory handle and will free it on
1018     object release.
1019  */
1020 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
1021 {
1022   NoStatStreamImpl* newStream;
1023
1024   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
1025   if (newStream!=0)
1026   {
1027     newStream->lpVtbl = &NoStatStreamImpl_Vtbl;
1028     newStream->ref    = 1;
1029     newStream->supportHandle = hGlobal;
1030
1031     if (!newStream->supportHandle)
1032       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
1033                                              GMEM_SHARE, 0);
1034     newStream->currentPosition.u.HighPart = 0;
1035     newStream->currentPosition.u.LowPart = 0;
1036     newStream->streamSize.u.HighPart = 0;
1037     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
1038   }
1039   return newStream;
1040 }
1041
1042
1043 static const IStreamVtbl NoStatStreamImpl_Vtbl =
1044 {
1045     NoStatStreamImpl_QueryInterface,
1046     NoStatStreamImpl_AddRef,
1047     NoStatStreamImpl_Release,
1048     NoStatStreamImpl_Read,
1049     NoStatStreamImpl_Write,
1050     NoStatStreamImpl_Seek,
1051     NoStatStreamImpl_SetSize,
1052     NoStatStreamImpl_CopyTo,
1053     NoStatStreamImpl_Commit,
1054     NoStatStreamImpl_Revert,
1055     NoStatStreamImpl_LockRegion,
1056     NoStatStreamImpl_UnlockRegion,
1057     NoStatStreamImpl_Stat,
1058     NoStatStreamImpl_Clone
1059 };