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