rpcrt4: Try a lot harder to resuse existing connections by comparing inside the RpcQu...
[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 = LoadLibraryA("oleaut32.dll");
430         pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
431         pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect");
432         if (!pOleLoadPicture)
433             return;
434
435         /* Test regular 1x1 pixel images of gif, jpg, bmp type */
436         test_pic(gifimage, sizeof(gifimage));
437         test_pic(jpgimage, sizeof(jpgimage));
438         test_pic(bmpimage, sizeof(bmpimage));
439         test_pic(gif4pixel, sizeof(gif4pixel));
440         /* FIXME: No PNG support yet in Wine or in older Windows... */
441         if (0) test_pic(pngimage, sizeof(pngimage));
442         test_empty_image();
443         test_empty_image_2();
444
445         test_Invoke();
446         test_OleCreatePictureIndirect();
447 }
448
449
450 /* Helper functions only ... */
451
452
453 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
454 {
455   GlobalFree(This->supportHandle);
456   This->supportHandle=0;
457   HeapFree(GetProcessHeap(), 0, This);
458 }
459
460 static ULONG WINAPI NoStatStreamImpl_AddRef(
461                 IStream* iface)
462 {
463   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
464   return InterlockedIncrement(&This->ref);
465 }
466
467 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
468                   IStream*     iface,
469                   REFIID         riid,        /* [in] */
470                   void**         ppvObject)   /* [iid_is][out] */
471 {
472   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
473   if (ppvObject==0) return E_INVALIDARG;
474   *ppvObject = 0;
475   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
476   {
477     *ppvObject = (IStream*)This;
478   }
479   else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
480   {
481     *ppvObject = (IStream*)This;
482   }
483
484   if ((*ppvObject)==0)
485     return E_NOINTERFACE;
486   NoStatStreamImpl_AddRef(iface);
487   return S_OK;
488 }
489
490 static ULONG WINAPI NoStatStreamImpl_Release(
491                 IStream* iface)
492 {
493   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
494   ULONG newRef = InterlockedDecrement(&This->ref);
495   if (newRef==0)
496     NoStatStreamImpl_Destroy(This);
497   return newRef;
498 }
499
500 static HRESULT WINAPI NoStatStreamImpl_Read(
501                   IStream*     iface,
502                   void*          pv,        /* [length_is][size_is][out] */
503                   ULONG          cb,        /* [in] */
504                   ULONG*         pcbRead)   /* [out] */
505 {
506   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
507   void* supportBuffer;
508   ULONG bytesReadBuffer;
509   ULONG bytesToReadFromBuffer;
510
511   if (pcbRead==0)
512     pcbRead = &bytesReadBuffer;
513   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
514   supportBuffer = GlobalLock(This->supportHandle);
515   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
516   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
517   *pcbRead = bytesToReadFromBuffer;
518   GlobalUnlock(This->supportHandle);
519   if(*pcbRead == cb)
520     return S_OK;
521   return S_FALSE;
522 }
523
524 static HRESULT WINAPI NoStatStreamImpl_Write(
525                   IStream*     iface,
526                   const void*    pv,          /* [size_is][in] */
527                   ULONG          cb,          /* [in] */
528                   ULONG*         pcbWritten)  /* [out] */
529 {
530   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
531   void*          supportBuffer;
532   ULARGE_INTEGER newSize;
533   ULONG          bytesWritten = 0;
534
535   if (pcbWritten == 0)
536     pcbWritten = &bytesWritten;
537   if (cb == 0)
538     return S_OK;
539   newSize.u.HighPart = 0;
540   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
541   if (newSize.u.LowPart > This->streamSize.u.LowPart)
542    IStream_SetSize(iface, newSize);
543
544   supportBuffer = GlobalLock(This->supportHandle);
545   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
546   This->currentPosition.u.LowPart+=cb;
547   *pcbWritten = cb;
548   GlobalUnlock(This->supportHandle);
549   return S_OK;
550 }
551
552 static HRESULT WINAPI NoStatStreamImpl_Seek(
553                   IStream*      iface,
554                   LARGE_INTEGER   dlibMove,         /* [in] */
555                   DWORD           dwOrigin,         /* [in] */
556                   ULARGE_INTEGER* plibNewPosition) /* [out] */
557 {
558   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
559   ULARGE_INTEGER newPosition;
560   switch (dwOrigin)
561   {
562     case STREAM_SEEK_SET:
563       newPosition.u.HighPart = 0;
564       newPosition.u.LowPart = 0;
565       break;
566     case STREAM_SEEK_CUR:
567       newPosition = This->currentPosition;
568       break;
569     case STREAM_SEEK_END:
570       newPosition = This->streamSize;
571       break;
572     default:
573       return STG_E_INVALIDFUNCTION;
574   }
575   if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
576       return STG_E_INVALIDFUNCTION;
577   newPosition.QuadPart += dlibMove.QuadPart;
578   if (plibNewPosition) *plibNewPosition = newPosition;
579   This->currentPosition = newPosition;
580   return S_OK;
581 }
582
583 static HRESULT WINAPI NoStatStreamImpl_SetSize(
584                                      IStream*      iface,
585                                      ULARGE_INTEGER  libNewSize)   /* [in] */
586 {
587   NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
588   HGLOBAL supportHandle;
589   if (libNewSize.u.HighPart != 0)
590     return STG_E_INVALIDFUNCTION;
591   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
592     return S_OK;
593   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
594   if (supportHandle == 0)
595     return STG_E_MEDIUMFULL;
596   This->supportHandle = supportHandle;
597   This->streamSize.u.LowPart = libNewSize.u.LowPart;
598   return S_OK;
599 }
600
601 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
602                                     IStream*      iface,
603                                     IStream*      pstm,         /* [unique][in] */
604                                     ULARGE_INTEGER  cb,           /* [in] */
605                                     ULARGE_INTEGER* pcbRead,      /* [out] */
606                                     ULARGE_INTEGER* pcbWritten)   /* [out] */
607 {
608   HRESULT        hr = S_OK;
609   BYTE           tmpBuffer[128];
610   ULONG          bytesRead, bytesWritten, copySize;
611   ULARGE_INTEGER totalBytesRead;
612   ULARGE_INTEGER totalBytesWritten;
613
614   if ( pstm == 0 )
615     return STG_E_INVALIDPOINTER;
616   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
617   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
618
619   while ( cb.u.LowPart > 0 )
620   {
621     if ( cb.u.LowPart >= 128 )
622       copySize = 128;
623     else
624       copySize = cb.u.LowPart;
625     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
626     totalBytesRead.u.LowPart += bytesRead;
627     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
628     totalBytesWritten.u.LowPart += bytesWritten;
629     if (bytesRead != bytesWritten)
630     {
631       hr = STG_E_MEDIUMFULL;
632       break;
633     }
634     if (bytesRead!=copySize)
635       cb.u.LowPart = 0;
636     else
637       cb.u.LowPart -= bytesRead;
638   }
639   if (pcbRead)
640   {
641     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
642     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
643   }
644
645   if (pcbWritten)
646   {
647     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
648     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
649   }
650   return hr;
651 }
652
653 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
654 {
655   return S_OK;
656 }
657 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
658
659 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
660                   IStream*       iface,
661                   ULARGE_INTEGER libOffset,   /* [in] */
662                   ULARGE_INTEGER cb,          /* [in] */
663                   DWORD          dwLockType)  /* [in] */
664 {
665   return S_OK;
666 }
667
668 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
669                   IStream*       iface,
670                   ULARGE_INTEGER libOffset,   /* [in] */
671                   ULARGE_INTEGER cb,          /* [in] */
672                   DWORD          dwLockType)  /* [in] */
673 {
674   return S_OK;
675 }
676
677 static HRESULT WINAPI NoStatStreamImpl_Stat(
678                   IStream*     iface,
679                   STATSTG*     pstatstg,     /* [out] */
680                   DWORD        grfStatFlag)  /* [in] */
681 {
682   return E_NOTIMPL;
683 }
684
685 static HRESULT WINAPI NoStatStreamImpl_Clone(
686                   IStream*     iface,
687                   IStream**    ppstm) /* [out] */
688 {
689   return E_NOTIMPL;
690 }
691 static const IStreamVtbl NoStatStreamImpl_Vtbl;
692
693 /*
694     Build an object that implements IStream, without IStream_Stat capabilities.
695     Receives a memory handle with data buffer. If memory handle is non-null,
696     it is assumed to be unlocked, otherwise an internal memory handle is allocated.
697     In any case the object takes ownership of memory handle and will free it on
698     object release.
699  */
700 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
701 {
702   NoStatStreamImpl* newStream;
703
704   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
705   if (newStream!=0)
706   {
707     newStream->lpVtbl = &NoStatStreamImpl_Vtbl;
708     newStream->ref    = 1;
709     newStream->supportHandle = hGlobal;
710
711     if (!newStream->supportHandle)
712       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
713                                              GMEM_SHARE, 0);
714     newStream->currentPosition.u.HighPart = 0;
715     newStream->currentPosition.u.LowPart = 0;
716     newStream->streamSize.u.HighPart = 0;
717     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
718   }
719   return newStream;
720 }
721
722
723 static const IStreamVtbl NoStatStreamImpl_Vtbl =
724 {
725     NoStatStreamImpl_QueryInterface,
726     NoStatStreamImpl_AddRef,
727     NoStatStreamImpl_Release,
728     NoStatStreamImpl_Read,
729     NoStatStreamImpl_Write,
730     NoStatStreamImpl_Seek,
731     NoStatStreamImpl_SetSize,
732     NoStatStreamImpl_CopyTo,
733     NoStatStreamImpl_Commit,
734     NoStatStreamImpl_Revert,
735     NoStatStreamImpl_LockRegion,
736     NoStatStreamImpl_UnlockRegion,
737     NoStatStreamImpl_Stat,
738     NoStatStreamImpl_Clone
739 };