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