winhttp: Implement IWinHttpRequest::Open.
[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 CONST_VTABLE
29 #define NONAMELESSUNION
30
31 #include "wine/test.h"
32 #include <windef.h>
33 #include <winbase.h>
34 #include <winuser.h>
35 #include <wingdi.h>
36 #include <winnls.h>
37 #include <winerror.h>
38 #include <winnt.h>
39
40 #include <urlmon.h>
41 #include <wtypes.h>
42 #include <olectl.h>
43 #include <objidl.h>
44
45 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
46
47 #define ole_expect(expr, expect) { \
48     HRESULT r = expr; \
49     ok(r == (expect), #expr " returned %x, expected %s (%x)\n", r, #expect, expect); \
50 }
51
52 #define ole_check(expr) ole_expect(expr, S_OK);
53
54 static HMODULE hOleaut32;
55
56 static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);
57 static HRESULT (WINAPI *pOleCreatePictureIndirect)(PICTDESC*,REFIID,BOOL,LPVOID*);
58
59 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
60
61 /* 1x1 pixel gif */
62 static const unsigned char gifimage[35] = {
63 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
64 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
65 0x01,0x00,0x3b
66 };
67
68 /* 1x1 pixel jpg */
69 static const unsigned char jpgimage[285] = {
70 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
71 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
72 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
73 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
74 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
75 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
76 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
77 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
78 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
79 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
80 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
81 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
82 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
83 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
84 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
85 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
86 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
87 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
88 };
89
90 /* 1x1 pixel png */
91 static const unsigned char pngimage[285] = {
92 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
93 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
94 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
95 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
96 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
97 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
98 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
99 };
100
101 /* 1x1 pixel bmp */
102 static const unsigned char bmpimage[66] = {
103 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
104 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
105 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
106 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
107 0x00,0x00
108 };
109
110 /* 2x2 pixel gif */
111 static const unsigned char gif4pixel[42] = {
112 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
113 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
114 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
115 };
116
117 /* APM with an empty metafile with some padding zeros - looks like under Window the
118  * metafile data should be at least 20 bytes */
119 static const unsigned char apmdata[] = {
120 0xd7,0xcd,0xc6,0x9a, 0x00,0x00,0x00,0x00, 0x00,0x00,0xee,0x02, 0xb1,0x03,0xa0,0x05,
121 0x00,0x00,0x00,0x00, 0xee,0x53,0x01,0x00, 0x09,0x00,0x00,0x03, 0x13,0x00,0x00,0x00,
122 0x01,0x00,0x05,0x00, 0x00,0x00,0x00,0x00, 0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
123 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
124 };
125
126 /* MF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
127 static const unsigned char metafile[] = {
128     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
129     0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
130     0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
131     0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
132     0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
133     0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
134     0x00, 0x00
135 };
136
137 /* EMF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
138 static const unsigned char enhmetafile[] = {
139     0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
140     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
142     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143     0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
144     0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
145     0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
146     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148     0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
149     0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
150     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151     0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
152     0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
153     0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
154     0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
156     0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
157     0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
158     0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
159     0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
160     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
162     0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
163     0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
164     0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
165     0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
166     0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
167     0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
168     0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
169     0x14, 0x00, 0x00, 0x00
170 };
171
172
173 typedef struct NoStatStreamImpl
174 {
175         IStream                 IStream_iface;
176         LONG                    ref;
177
178         HGLOBAL                 supportHandle;
179         ULARGE_INTEGER          streamSize;
180         ULARGE_INTEGER          currentPosition;
181 } NoStatStreamImpl;
182
183 static IStream* NoStatStream_Construct(HGLOBAL hGlobal);
184
185 static void
186 test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
187 {
188         IPicture*       pic = NULL;
189         HRESULT         hres;
190         LPVOID          pvObj = NULL;
191         OLE_HANDLE      handle, hPal;
192         OLE_XSIZE_HIMETRIC      width;
193         OLE_YSIZE_HIMETRIC      height;
194         short           type;
195         DWORD           attr;
196         ULONG           res;
197
198         pvObj = NULL;
199         hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
200         pic = pvObj;
201
202         ok(hres == S_OK,"OLP (NULL,..) does not return 0, but 0x%08x\n",hres);
203         ok(pic != NULL,"OLP (NULL,..) returns NULL, instead of !NULL\n");
204         if (pic == NULL)
205                 return;
206
207         pvObj = NULL;
208         hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);
209
210         ok(hres == S_OK,"IPicture_QI does not return S_OK, but 0x%08x\n", hres);
211         ok(pvObj != NULL,"IPicture_QI does return NULL, instead of a ptr\n");
212
213         IPicture_Release ((IPicture*)pvObj);
214
215         handle = 0;
216         hres = IPicture_get_Handle (pic, &handle);
217         ok(hres == S_OK,"IPicture_get_Handle does not return S_OK, but 0x%08x\n", hres);
218         ok(handle != 0, "IPicture_get_Handle returns a NULL handle, but it should be non NULL\n");
219
220         if (handle)
221         {
222             BITMAP bmp;
223             GetObject(UlongToHandle(handle), sizeof(BITMAP), &bmp);
224             todo_wine ok(bmp.bmBits != 0, "not a dib\n");
225         }
226
227         width = 0;
228         hres = IPicture_get_Width (pic, &width);
229         ok(hres == S_OK,"IPicture_get_Width does not return S_OK, but 0x%08x\n", hres);
230         ok(width != 0, "IPicture_get_Width returns 0, but it should not be 0.\n");
231
232         height = 0;
233         hres = IPicture_get_Height (pic, &height);
234         ok(hres == S_OK,"IPicture_get_Height does not return S_OK, but 0x%08x\n", hres);
235         ok(height != 0, "IPicture_get_Height returns 0, but it should not be 0.\n");
236
237         type = 0;
238         hres = IPicture_get_Type (pic, &type);
239         ok(hres == S_OK,"IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
240         ok(type == PICTYPE_BITMAP, "IPicture_get_Type returns %d, but it should be PICTYPE_BITMAP(%d).\n", type, PICTYPE_BITMAP);
241
242         attr = 0;
243         hres = IPicture_get_Attributes (pic, &attr);
244         ok(hres == S_OK,"IPicture_get_Attributes does not return S_OK, but 0x%08x\n", hres);
245         ok(attr == 0, "IPicture_get_Attributes returns %d, but it should be 0.\n", attr);
246
247         hPal = 0;
248         hres = IPicture_get_hPal (pic, &hPal);
249         ok(hres == S_OK,"IPicture_get_hPal does not return S_OK, but 0x%08x\n", hres);
250         /* a single pixel b/w image has no palette */
251         ok(hPal == 0, "IPicture_get_hPal returns %d, but it should be 0.\n", hPal);
252
253         res = IPicture_Release (pic);
254         ok (res == 0, "refcount after release is %d, but should be 0?\n", res);
255 }
256
257 static void
258 test_pic(const unsigned char *imgdata, unsigned int imgsize)
259 {
260         LPSTREAM        stream;
261         HGLOBAL         hglob;
262         LPBYTE          data;
263         HRESULT         hres;
264         LARGE_INTEGER   seekto;
265         ULARGE_INTEGER  newpos1;
266         DWORD *         header;
267         unsigned int    i,j;
268
269         /* Let the fun begin */
270         hglob = GlobalAlloc (0, imgsize);
271         data = GlobalLock (hglob);
272         memcpy(data, imgdata, imgsize);
273         GlobalUnlock(hglob); data = NULL;
274
275         hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
276         ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
277
278         memset(&seekto,0,sizeof(seekto));
279         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
280         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
281         test_pic_with_stream(stream, imgsize);
282         
283         IStream_Release(stream);
284
285         /* again with Non Statable and Non Seekable stream */
286         stream = NoStatStream_Construct(hglob);
287         hglob = 0;  /* Non-statable impl always deletes on release */
288         test_pic_with_stream(stream, 0);
289
290         IStream_Release(stream);
291         for (i = 1; i <= 8; i++) {
292                 /* more fun!!! */
293                 hglob = GlobalAlloc (0, imgsize + i * (2 * sizeof(DWORD)));
294                 data = GlobalLock (hglob);
295                 header = (DWORD *)data;
296
297                 /* multiple copies of header */
298                 memcpy(data,"lt\0\0",4);
299                 header[1] = imgsize;
300                 for (j = 2; j <= i; j++) {
301                         memcpy(&(header[2 * (j - 1)]), header, 2 * sizeof(DWORD));
302                 }
303                 memcpy(data + i * (2 * sizeof(DWORD)), imgdata, imgsize);
304                 GlobalUnlock(hglob); data = NULL;
305
306                 hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
307                 ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
308
309                 memset(&seekto,0,sizeof(seekto));
310                 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
311                 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
312                 test_pic_with_stream(stream, imgsize);
313         
314                 IStream_Release(stream);
315
316                 /* again with Non Statable and Non Seekable stream */
317                 stream = NoStatStream_Construct(hglob);
318                 hglob = 0;  /* Non-statable impl always deletes on release */
319                 test_pic_with_stream(stream, 0);
320
321                 IStream_Release(stream);
322         }
323 }
324
325 static void test_empty_image(void) {
326         LPBYTE          data;
327         LPSTREAM        stream;
328         IPicture*       pic = NULL;
329         HRESULT         hres;
330         LPVOID          pvObj = NULL;
331         HGLOBAL         hglob;
332         OLE_HANDLE      handle;
333         ULARGE_INTEGER  newpos1;
334         LARGE_INTEGER   seekto;
335         short           type;
336         DWORD           attr;
337
338         /* Empty image. Happens occasionally in VB programs. */
339         hglob = GlobalAlloc (0, 8);
340         data = GlobalLock (hglob);
341         memcpy(data,"lt\0\0",4);
342         ((DWORD*)data)[1] = 0;
343         hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
344         ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
345
346         memset(&seekto,0,sizeof(seekto));
347         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
348         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
349
350         pvObj = NULL;
351         hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
352         pic = pvObj;
353         ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
354         ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
355
356         hres = IPicture_get_Type (pic, &type);
357         ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
358         ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
359
360         attr = 0xdeadbeef;
361         hres = IPicture_get_Attributes (pic, &attr);
362         ok (hres == S_OK,"empty picture get attributes failed with hres 0x%08x\n", hres);
363         ok (attr == 0,"attr is %d, but should be 0\n", attr);
364
365         hres = IPicture_get_Handle (pic, &handle);
366         ok (hres == S_OK,"empty picture get handle failed with hres 0x%08x\n", hres);
367         ok (handle == 0, "empty picture get handle did not return 0, but 0x%08x\n", handle);
368         IPicture_Release (pic);
369         IStream_Release (stream);
370 }
371
372 static void test_empty_image_2(void) {
373         LPBYTE          data;
374         LPSTREAM        stream;
375         IPicture*       pic = NULL;
376         HRESULT         hres;
377         LPVOID          pvObj = NULL;
378         HGLOBAL         hglob;
379         ULARGE_INTEGER  newpos1;
380         LARGE_INTEGER   seekto;
381         short           type;
382
383         /* Empty image at random stream position. */
384         hglob = GlobalAlloc (0, 200);
385         data = GlobalLock (hglob);
386         data += 42;
387         memcpy(data,"lt\0\0",4);
388         ((DWORD*)data)[1] = 0;
389         hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
390         ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
391
392         memset(&seekto,0,sizeof(seekto));
393         seekto.u.LowPart = 42;
394         hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
395         ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
396
397         pvObj = NULL;
398         hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
399         pic = pvObj;
400         ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
401         ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
402
403         hres = IPicture_get_Type (pic, &type);
404         ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
405         ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
406
407         IPicture_Release (pic);
408         IStream_Release (stream);
409 }
410
411 static void test_Invoke(void)
412 {
413     IPictureDisp *picdisp;
414     HRESULT hr;
415     VARIANTARG vararg;
416     DISPPARAMS dispparams;
417     VARIANT varresult;
418     IStream *stream;
419     HGLOBAL hglob;
420     void *data;
421
422     hglob = GlobalAlloc (0, sizeof(gifimage));
423     data = GlobalLock(hglob);
424     memcpy(data, gifimage, sizeof(gifimage));
425     GlobalUnlock(hglob);
426
427     hr = CreateStreamOnHGlobal (hglob, FALSE, &stream);
428     ok_ole_success(hr, "CreateStreamOnHGlobal");
429
430     hr = pOleLoadPicture(stream, sizeof(gifimage), TRUE, &IID_IPictureDisp, (void **)&picdisp);
431     IStream_Release(stream);
432     GlobalFree(hglob);
433     ok_ole_success(hr, "OleLoadPicture");
434
435     V_VT(&vararg) = VT_BOOL;
436     V_BOOL(&vararg) = VARIANT_FALSE;
437     dispparams.cNamedArgs = 0;
438     dispparams.rgdispidNamedArgs = NULL;
439     dispparams.cArgs = 1;
440     dispparams.rgvarg = &vararg;
441     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IPictureDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
442     ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
443     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IUnknown, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
444     ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
445
446     dispparams.cArgs = 0;
447     dispparams.rgvarg = NULL;
448     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
449     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
450
451     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, NULL, NULL, NULL, NULL);
452     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
453
454     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, NULL, NULL, NULL);
455     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
456
457     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
458     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
459
460     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
461     ok_ole_success(hr, "IPictureDisp_Invoke");
462     ok(V_VT(&varresult) == VT_I4, "V_VT(&varresult) should have been VT_UINT instead of %d\n", V_VT(&varresult));
463
464     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
465     ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
466
467     hr = IPictureDisp_Invoke(picdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
468     ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
469
470     dispparams.cArgs = 1;
471     dispparams.rgvarg = &vararg;
472     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
473     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
474
475     dispparams.cArgs = 1;
476     dispparams.rgvarg = &vararg;
477     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
478     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
479
480     IPictureDisp_Release(picdisp);
481 }
482
483 static void test_OleCreatePictureIndirect(void)
484 {
485     OLE_HANDLE handle;
486     IPicture *pict;
487     HRESULT hr;
488     short type;
489
490     if(!pOleCreatePictureIndirect)
491     {
492         win_skip("Skipping OleCreatePictureIndirect tests\n");
493         return;
494     }
495
496 if (0)
497 {
498     /* crashes on native */
499     pOleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, NULL);
500 }
501
502     hr = pOleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
503     ok(hr == S_OK, "hr %08x\n", hr);
504
505     type = PICTYPE_NONE;
506     hr = IPicture_get_Type(pict, &type);
507     ok(hr == S_OK, "hr %08x\n", hr);
508     ok(type == PICTYPE_UNINITIALIZED, "type %d\n", type);
509
510     handle = 0xdeadbeef;
511     hr = IPicture_get_Handle(pict, &handle);
512     ok(hr == S_OK, "hr %08x\n", hr);
513     ok(handle == 0, "handle %08x\n", handle);
514
515     IPicture_Release(pict);
516 }
517
518 static void test_apm(void)
519 {
520     OLE_HANDLE handle;
521     LPSTREAM stream;
522     IPicture *pict;
523     HGLOBAL hglob;
524     LPBYTE *data;
525     LONG cxy;
526     BOOL keep;
527     short type;
528
529     hglob = GlobalAlloc (0, sizeof(apmdata));
530     data = GlobalLock(hglob);
531     memcpy(data, apmdata, sizeof(apmdata));
532
533     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
534     ole_check(OleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
535
536     ole_check(IPicture_get_Handle(pict, &handle));
537     ok(handle != 0, "handle is null\n");
538
539     ole_check(IPicture_get_Type(pict, &type));
540     expect_eq(type, PICTYPE_METAFILE, short, "%d");
541
542     ole_check(IPicture_get_Height(pict, &cxy));
543     expect_eq(cxy,  1667, LONG, "%d");
544
545     ole_check(IPicture_get_Width(pict, &cxy));
546     expect_eq(cxy,  1323, LONG, "%d");
547
548     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
549     todo_wine expect_eq(keep, FALSE, LONG, "%d");
550
551     ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
552     IPicture_Release(pict);
553     IStream_Release(stream);
554 }
555
556 static void test_metafile(void)
557 {
558     LPSTREAM stream;
559     IPicture *pict;
560     HGLOBAL hglob;
561     LPBYTE *data;
562
563     hglob = GlobalAlloc (0, sizeof(metafile));
564     data = GlobalLock(hglob);
565     memcpy(data, metafile, sizeof(metafile));
566
567     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
568     /* Windows does not load simple metafiles */
569     ole_expect(OleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
570
571     IStream_Release(stream);
572 }
573
574 static void test_enhmetafile(void)
575 {
576     OLE_HANDLE handle;
577     LPSTREAM stream;
578     IPicture *pict;
579     HGLOBAL hglob;
580     LPBYTE *data;
581     LONG cxy;
582     BOOL keep;
583     short type;
584
585     hglob = GlobalAlloc (0, sizeof(enhmetafile));
586     data = GlobalLock(hglob);
587     memcpy(data, enhmetafile, sizeof(enhmetafile));
588
589     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
590     ole_check(OleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
591
592     ole_check(IPicture_get_Handle(pict, &handle));
593     ok(handle != 0, "handle is null\n");
594
595     ole_check(IPicture_get_Type(pict, &type));
596     expect_eq(type, PICTYPE_ENHMETAFILE, short, "%d");
597
598     ole_check(IPicture_get_Height(pict, &cxy));
599     expect_eq(cxy, -23, LONG, "%d");
600
601     ole_check(IPicture_get_Width(pict, &cxy));
602     expect_eq(cxy, -25, LONG, "%d");
603
604     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
605     todo_wine expect_eq(keep, FALSE, LONG, "%d");
606
607     IPicture_Release(pict);
608     IStream_Release(stream);
609 }
610
611 static void test_Render(void)
612 {
613     IPicture *pic;
614     HRESULT hres;
615     short type;
616     PICTDESC desc;
617     OLE_XSIZE_HIMETRIC pWidth;
618     OLE_YSIZE_HIMETRIC pHeight;
619     COLORREF result, expected;
620     HDC hdc = GetDC(0);
621
622     /* test IPicture::Render return code on uninitialized picture */
623     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
624     hres = IPicture_get_Type(pic, &type);
625     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
626     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
627     /* zero dimensions */
628     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
629     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
630     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
631     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
632     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
633     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
634     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
635     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
636     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
637     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
638     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
639     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
640     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
641     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
642     /* nonzero dimensions, PICTYPE_UNINITIALIZED */
643     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL);
644     ole_expect(hres, S_OK);
645     IPicture_Release(pic);
646
647     desc.cbSizeofstruct = sizeof(PICTDESC);
648     desc.picType = PICTYPE_ICON;
649     desc.u.icon.hicon = LoadIcon(NULL, IDI_APPLICATION);
650     if(!desc.u.icon.hicon){
651         win_skip("LoadIcon failed. Skipping...\n");
652         ReleaseDC(NULL, hdc);
653         return;
654     }
655
656     OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (VOID**)&pic);
657     /* zero dimensions, PICTYPE_ICON */
658     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
659     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
660     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
661     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
662     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
663     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
664     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
665     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
666     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
667     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
668     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
669     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
670     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
671     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
672
673     /* Check if target size and position is respected */
674     IPicture_get_Width(pic, &pWidth);
675     IPicture_get_Height(pic, &pHeight);
676
677     SetPixelV(hdc, 0, 0, 0x00F0F0F0);
678     SetPixelV(hdc, 5, 5, 0x00F0F0F0);
679     SetPixelV(hdc, 10, 10, 0x00F0F0F0);
680     expected = GetPixel(hdc, 0, 0);
681
682     hres = IPicture_Render(pic, hdc, 1, 1, 9, 9, 0, 0, pWidth, -pHeight, NULL);
683     ole_expect(hres, S_OK);
684
685     if(hres != S_OK) {
686         IPicture_Release(pic);
687         ReleaseDC(NULL, hdc);
688         return;
689     }
690
691     /* Evaluate the rendered Icon */
692     result = GetPixel(hdc, 0, 0);
693     ok(result == expected,
694        "Color at 0,0 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
695     result = GetPixel(hdc, 5, 5);
696     ok(result != expected ||
697         broken(result == expected), /* WinNT 4.0 and older may claim they drew */
698                                     /* the icon, even if they didn't. */
699        "Color at 5,5 should have changed, but still was 0x%06X\n", expected);
700     result = GetPixel(hdc, 10, 10);
701     ok(result == expected,
702        "Color at 10,10 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
703
704     IPicture_Release(pic);
705     ReleaseDC(NULL, hdc);
706 }
707
708 static void test_get_Attributes(void)
709 {
710     IPicture *pic;
711     HRESULT hres;
712     short type;
713     DWORD attr;
714
715     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
716     hres = IPicture_get_Type(pic, &type);
717     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
718     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
719
720     hres = IPicture_get_Attributes(pic, NULL);
721     ole_expect(hres, E_POINTER);
722
723     attr = 0xdeadbeef;
724     hres = IPicture_get_Attributes(pic, &attr);
725     ole_expect(hres, S_OK);
726     ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %d\n", attr);
727
728     IPicture_Release(pic);
729 }
730
731 static void test_get_Handle(void)
732 {
733     IPicture *pic;
734     HRESULT hres;
735
736     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
737
738     hres = IPicture_get_Handle(pic, NULL);
739     ole_expect(hres, E_POINTER);
740
741     IPicture_Release(pic);
742 }
743
744 static void test_get_Type(void)
745 {
746     IPicture *pic;
747     HRESULT hres;
748
749     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
750
751     hres = IPicture_get_Type(pic, NULL);
752     ole_expect(hres, E_POINTER);
753
754     IPicture_Release(pic);
755 }
756
757 static void test_OleLoadPicturePath(void)
758 {
759     static WCHAR emptyW[] = {0};
760
761     IPicture *pic;
762     HRESULT hres;
763     int i;
764     char temp_path[MAX_PATH];
765     char temp_file[MAX_PATH];
766     WCHAR temp_fileW[MAX_PATH + 5] = {'f','i','l','e',':','/','/','/'};
767     HANDLE file;
768     DWORD size;
769     WCHAR *ptr;
770
771     const struct
772     {
773         LPOLESTR szURLorPath;
774         REFIID riid;
775         IPicture **pic;
776     } invalid_parameters[] =
777     {
778         {NULL,  NULL,          NULL},
779         {NULL,  NULL,          &pic},
780         {NULL,  &IID_IPicture, NULL},
781         {NULL,  &IID_IPicture, &pic},
782         {emptyW, NULL,          NULL},
783         {emptyW, &IID_IPicture, NULL},
784     };
785
786     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
787     {
788         pic = (IPicture *)0xdeadbeef;
789         hres = OleLoadPicturePath(invalid_parameters[i].szURLorPath, NULL, 0, 0,
790                                   invalid_parameters[i].riid,
791                                   (void **)invalid_parameters[i].pic);
792         ok(hres == E_INVALIDARG,
793            "[%d] Expected OleLoadPicturePath to return E_INVALIDARG, got 0x%08x\n", i, hres);
794         ok(pic == (IPicture *)0xdeadbeef,
795            "[%d] Expected output pointer to be 0xdeadbeef, got %p\n", i, pic);
796     }
797
798     pic = (IPicture *)0xdeadbeef;
799     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, NULL, (void **)&pic);
800     todo_wine
801     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
802        broken(hres == E_UNEXPECTED) || /* NT4 */
803        broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
804        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
805     ok(pic == NULL,
806        "Expected the output interface pointer to be NULL, got %p\n", pic);
807
808     pic = (IPicture *)0xdeadbeef;
809     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
810     todo_wine
811     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
812        broken(hres == E_UNEXPECTED) || /* NT4 */
813        broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
814        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
815     ok(pic == NULL,
816        "Expected the output interface pointer to be NULL, got %p\n", pic);
817
818     /* Create a local temporary image file for testing. */
819     GetTempPathA(sizeof(temp_path), temp_path);
820     GetTempFileNameA(temp_path, "bmp", 0, temp_file);
821     file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
822                        FILE_ATTRIBUTE_NORMAL, NULL);
823     WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
824     CloseHandle(file);
825
826     MultiByteToWideChar(CP_ACP, 0, temp_file, -1, temp_fileW + 8, sizeof(temp_fileW)/sizeof(WCHAR) - 8);
827
828     /* Try a normal DOS path. */
829     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
830     ok(hres == S_OK ||
831        broken(hres == E_UNEXPECTED), /* NT4 */
832        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
833     if (pic)
834         IPicture_Release(pic);
835
836     /* Try a DOS path with tacked on "file:". */
837     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
838     ok(hres == S_OK ||
839        broken(hres == E_UNEXPECTED), /* NT4 */
840        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
841     if (pic)
842         IPicture_Release(pic);
843
844     DeleteFileA(temp_file);
845
846     /* Try with a nonexistent file. */
847     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
848     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
849        broken(hres == E_UNEXPECTED) || /* NT4 */
850        broken(hres == E_FAIL), /*Win2k */
851        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
852
853     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
854     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
855        broken(hres == E_UNEXPECTED) || /* NT4 */
856        broken(hres == E_FAIL), /* Win2k */
857        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
858
859     file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
860                        FILE_ATTRIBUTE_NORMAL, NULL);
861     WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
862     CloseHandle(file);
863
864     /* Try a "file:" URL with slash separators. */
865     ptr = temp_fileW + 8;
866     while (*ptr)
867     {
868         if (*ptr == '\\')
869             *ptr = '/';
870         ptr++;
871     }
872
873     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
874     ok(hres == S_OK ||
875        broken(hres == E_UNEXPECTED), /* NT4 */
876        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
877     if (pic)
878         IPicture_Release(pic);
879
880     DeleteFileA(temp_file);
881
882     /* Try with a nonexistent file. */
883     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
884     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
885        broken(hres == E_UNEXPECTED) || /* NT4 */
886        broken(hres == E_FAIL), /* Win2k */
887        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
888 }
889
890 static void test_himetric(void)
891 {
892     static const BYTE bmp_bits[1024];
893     OLE_XSIZE_HIMETRIC cx;
894     OLE_YSIZE_HIMETRIC cy;
895     IPicture *pic;
896     PICTDESC desc;
897     HBITMAP bmp;
898     HRESULT hr;
899     HICON icon;
900     HDC hdc;
901     INT d;
902
903     if (!pOleCreatePictureIndirect)
904     {
905         win_skip("OleCreatePictureIndirect not available\n");
906         return;
907     }
908
909     desc.cbSizeofstruct = sizeof(desc);
910     desc.picType = PICTYPE_BITMAP;
911     desc.u.bmp.hpal = NULL;
912
913     hdc = CreateCompatibleDC(0);
914
915     bmp = CreateBitmap(1.9 * GetDeviceCaps(hdc, LOGPIXELSX),
916                        1.9 * GetDeviceCaps(hdc, LOGPIXELSY), 1, 1, NULL);
917
918     desc.u.bmp.hbitmap = bmp;
919
920     /* size in himetric units reported rounded up to next integer value */
921     hr = pOleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
922     ok(hr == S_OK, "got 0x%08x\n", hr);
923
924     cx = 0;
925     d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSX)), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
926     hr = IPicture_get_Width(pic, &cx);
927     ok(hr == S_OK, "got 0x%08x\n", hr);
928     ok(cx == d, "got %d, expected %d\n", cx, d);
929
930     cy = 0;
931     d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSY)), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
932     hr = IPicture_get_Height(pic, &cy);
933     ok(hr == S_OK, "got 0x%08x\n", hr);
934     ok(cy == d, "got %d, expected %d\n", cy, d);
935
936     DeleteObject(bmp);
937     IPicture_Release(pic);
938
939     /* same thing with icon */
940     icon = CreateIcon(NULL, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
941                       1, 1, bmp_bits, bmp_bits);
942     ok(icon != NULL, "failed to create icon\n");
943
944     desc.picType = PICTYPE_ICON;
945     desc.u.icon.hicon = icon;
946
947     hr = pOleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
948     ok(hr == S_OK, "got 0x%08x\n", hr);
949
950     cx = 0;
951     d = MulDiv(GetSystemMetrics(SM_CXICON), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
952     hr = IPicture_get_Width(pic, &cx);
953     ok(hr == S_OK, "got 0x%08x\n", hr);
954     ok(cx == d, "got %d, expected %d\n", cx, d);
955
956     cy = 0;
957     d = MulDiv(GetSystemMetrics(SM_CYICON), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
958     hr = IPicture_get_Height(pic, &cy);
959     ok(hr == S_OK, "got 0x%08x\n", hr);
960     ok(cy == d, "got %d, expected %d\n", cy, d);
961
962     IPicture_Release(pic);
963     DestroyIcon(icon);
964
965     DeleteDC(hdc);
966 }
967
968 START_TEST(olepicture)
969 {
970         hOleaut32 = GetModuleHandleA("oleaut32.dll");
971         pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
972         pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect");
973         if (!pOleLoadPicture)
974         {
975             win_skip("OleLoadPicture is not available\n");
976             return;
977         }
978
979         /* Test regular 1x1 pixel images of gif, jpg, bmp type */
980         test_pic(gifimage, sizeof(gifimage));
981         test_pic(jpgimage, sizeof(jpgimage));
982         test_pic(bmpimage, sizeof(bmpimage));
983         test_pic(gif4pixel, sizeof(gif4pixel));
984         /* FIXME: No PNG support in Windows... */
985         if (0) test_pic(pngimage, sizeof(pngimage));
986         test_empty_image();
987         test_empty_image_2();
988         test_apm();
989         test_metafile();
990         test_enhmetafile();
991
992     test_Invoke();
993     test_OleCreatePictureIndirect();
994     test_Render();
995     test_get_Attributes();
996     test_get_Handle();
997     test_get_Type();
998     test_OleLoadPicturePath();
999     test_himetric();
1000 }
1001
1002
1003 /* Helper functions only ... */
1004
1005
1006 static inline NoStatStreamImpl *impl_from_IStream(IStream *iface)
1007 {
1008   return CONTAINING_RECORD(iface, NoStatStreamImpl, IStream_iface);
1009 }
1010
1011 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
1012 {
1013   GlobalFree(This->supportHandle);
1014   This->supportHandle=0;
1015   HeapFree(GetProcessHeap(), 0, This);
1016 }
1017
1018 static ULONG WINAPI NoStatStreamImpl_AddRef(
1019                 IStream* iface)
1020 {
1021   NoStatStreamImpl* const This = impl_from_IStream(iface);
1022   return InterlockedIncrement(&This->ref);
1023 }
1024
1025 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
1026                   IStream*     iface,
1027                   REFIID         riid,        /* [in] */
1028                   void**         ppvObject)   /* [iid_is][out] */
1029 {
1030   NoStatStreamImpl* const This = impl_from_IStream(iface);
1031   if (ppvObject==0) return E_INVALIDARG;
1032   *ppvObject = 0;
1033   if (IsEqualIID(&IID_IUnknown, riid))
1034   {
1035     *ppvObject = This;
1036   }
1037   else if (IsEqualIID(&IID_IStream, riid))
1038   {
1039     *ppvObject = This;
1040   }
1041
1042   if ((*ppvObject)==0)
1043     return E_NOINTERFACE;
1044   NoStatStreamImpl_AddRef(iface);
1045   return S_OK;
1046 }
1047
1048 static ULONG WINAPI NoStatStreamImpl_Release(
1049                 IStream* iface)
1050 {
1051   NoStatStreamImpl* const This = impl_from_IStream(iface);
1052   ULONG newRef = InterlockedDecrement(&This->ref);
1053   if (newRef==0)
1054     NoStatStreamImpl_Destroy(This);
1055   return newRef;
1056 }
1057
1058 static HRESULT WINAPI NoStatStreamImpl_Read(
1059                   IStream*     iface,
1060                   void*          pv,        /* [length_is][size_is][out] */
1061                   ULONG          cb,        /* [in] */
1062                   ULONG*         pcbRead)   /* [out] */
1063 {
1064   NoStatStreamImpl* const This = impl_from_IStream(iface);
1065   void* supportBuffer;
1066   ULONG bytesReadBuffer;
1067   ULONG bytesToReadFromBuffer;
1068
1069   if (pcbRead==0)
1070     pcbRead = &bytesReadBuffer;
1071   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
1072   supportBuffer = GlobalLock(This->supportHandle);
1073   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
1074   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
1075   *pcbRead = bytesToReadFromBuffer;
1076   GlobalUnlock(This->supportHandle);
1077   if(*pcbRead == cb)
1078     return S_OK;
1079   return S_FALSE;
1080 }
1081
1082 static HRESULT WINAPI NoStatStreamImpl_Write(
1083                   IStream*     iface,
1084                   const void*    pv,          /* [size_is][in] */
1085                   ULONG          cb,          /* [in] */
1086                   ULONG*         pcbWritten)  /* [out] */
1087 {
1088   NoStatStreamImpl* const This = impl_from_IStream(iface);
1089   void*          supportBuffer;
1090   ULARGE_INTEGER newSize;
1091   ULONG          bytesWritten = 0;
1092
1093   if (pcbWritten == 0)
1094     pcbWritten = &bytesWritten;
1095   if (cb == 0)
1096     return S_OK;
1097   newSize.u.HighPart = 0;
1098   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
1099   if (newSize.u.LowPart > This->streamSize.u.LowPart)
1100    IStream_SetSize(iface, newSize);
1101
1102   supportBuffer = GlobalLock(This->supportHandle);
1103   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
1104   This->currentPosition.u.LowPart+=cb;
1105   *pcbWritten = cb;
1106   GlobalUnlock(This->supportHandle);
1107   return S_OK;
1108 }
1109
1110 static HRESULT WINAPI NoStatStreamImpl_Seek(
1111                   IStream*      iface,
1112                   LARGE_INTEGER   dlibMove,         /* [in] */
1113                   DWORD           dwOrigin,         /* [in] */
1114                   ULARGE_INTEGER* plibNewPosition) /* [out] */
1115 {
1116   NoStatStreamImpl* const This = impl_from_IStream(iface);
1117   ULARGE_INTEGER newPosition;
1118   switch (dwOrigin)
1119   {
1120     case STREAM_SEEK_SET:
1121       newPosition.u.HighPart = 0;
1122       newPosition.u.LowPart = 0;
1123       break;
1124     case STREAM_SEEK_CUR:
1125       newPosition = This->currentPosition;
1126       break;
1127     case STREAM_SEEK_END:
1128       newPosition = This->streamSize;
1129       break;
1130     default:
1131       return STG_E_INVALIDFUNCTION;
1132   }
1133   if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
1134       return STG_E_INVALIDFUNCTION;
1135   newPosition.QuadPart += dlibMove.QuadPart;
1136   if (plibNewPosition) *plibNewPosition = newPosition;
1137   This->currentPosition = newPosition;
1138   return S_OK;
1139 }
1140
1141 static HRESULT WINAPI NoStatStreamImpl_SetSize(
1142                                      IStream*      iface,
1143                                      ULARGE_INTEGER  libNewSize)   /* [in] */
1144 {
1145   NoStatStreamImpl* const This = impl_from_IStream(iface);
1146   HGLOBAL supportHandle;
1147   if (libNewSize.u.HighPart != 0)
1148     return STG_E_INVALIDFUNCTION;
1149   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
1150     return S_OK;
1151   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
1152   if (supportHandle == 0)
1153     return STG_E_MEDIUMFULL;
1154   This->supportHandle = supportHandle;
1155   This->streamSize.u.LowPart = libNewSize.u.LowPart;
1156   return S_OK;
1157 }
1158
1159 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
1160                                     IStream*      iface,
1161                                     IStream*      pstm,         /* [unique][in] */
1162                                     ULARGE_INTEGER  cb,           /* [in] */
1163                                     ULARGE_INTEGER* pcbRead,      /* [out] */
1164                                     ULARGE_INTEGER* pcbWritten)   /* [out] */
1165 {
1166   HRESULT        hr = S_OK;
1167   BYTE           tmpBuffer[128];
1168   ULONG          bytesRead, bytesWritten, copySize;
1169   ULARGE_INTEGER totalBytesRead;
1170   ULARGE_INTEGER totalBytesWritten;
1171
1172   if ( pstm == 0 )
1173     return STG_E_INVALIDPOINTER;
1174   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
1175   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
1176
1177   while ( cb.u.LowPart > 0 )
1178   {
1179     if ( cb.u.LowPart >= 128 )
1180       copySize = 128;
1181     else
1182       copySize = cb.u.LowPart;
1183     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1184     totalBytesRead.u.LowPart += bytesRead;
1185     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1186     totalBytesWritten.u.LowPart += bytesWritten;
1187     if (bytesRead != bytesWritten)
1188     {
1189       hr = STG_E_MEDIUMFULL;
1190       break;
1191     }
1192     if (bytesRead!=copySize)
1193       cb.u.LowPart = 0;
1194     else
1195       cb.u.LowPart -= bytesRead;
1196   }
1197   if (pcbRead)
1198   {
1199     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
1200     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
1201   }
1202
1203   if (pcbWritten)
1204   {
1205     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
1206     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
1207   }
1208   return hr;
1209 }
1210
1211 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
1212 {
1213   return S_OK;
1214 }
1215 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
1216
1217 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
1218                   IStream*       iface,
1219                   ULARGE_INTEGER libOffset,   /* [in] */
1220                   ULARGE_INTEGER cb,          /* [in] */
1221                   DWORD          dwLockType)  /* [in] */
1222 {
1223   return S_OK;
1224 }
1225
1226 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
1227                   IStream*       iface,
1228                   ULARGE_INTEGER libOffset,   /* [in] */
1229                   ULARGE_INTEGER cb,          /* [in] */
1230                   DWORD          dwLockType)  /* [in] */
1231 {
1232   return S_OK;
1233 }
1234
1235 static HRESULT WINAPI NoStatStreamImpl_Stat(
1236                   IStream*     iface,
1237                   STATSTG*     pstatstg,     /* [out] */
1238                   DWORD        grfStatFlag)  /* [in] */
1239 {
1240   return E_NOTIMPL;
1241 }
1242
1243 static HRESULT WINAPI NoStatStreamImpl_Clone(
1244                   IStream*     iface,
1245                   IStream**    ppstm) /* [out] */
1246 {
1247   return E_NOTIMPL;
1248 }
1249 static const IStreamVtbl NoStatStreamImpl_Vtbl;
1250
1251 /*
1252     Build an object that implements IStream, without IStream_Stat capabilities.
1253     Receives a memory handle with data buffer. If memory handle is non-null,
1254     it is assumed to be unlocked, otherwise an internal memory handle is allocated.
1255     In any case the object takes ownership of memory handle and will free it on
1256     object release.
1257  */
1258 static IStream* NoStatStream_Construct(HGLOBAL hGlobal)
1259 {
1260   NoStatStreamImpl* newStream;
1261
1262   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
1263   if (newStream!=0)
1264   {
1265     newStream->IStream_iface.lpVtbl = &NoStatStreamImpl_Vtbl;
1266     newStream->ref    = 1;
1267     newStream->supportHandle = hGlobal;
1268
1269     if (!newStream->supportHandle)
1270       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
1271                                              GMEM_SHARE, 0);
1272     newStream->currentPosition.u.HighPart = 0;
1273     newStream->currentPosition.u.LowPart = 0;
1274     newStream->streamSize.u.HighPart = 0;
1275     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
1276   }
1277   return &newStream->IStream_iface;
1278 }
1279
1280
1281 static const IStreamVtbl NoStatStreamImpl_Vtbl =
1282 {
1283     NoStatStreamImpl_QueryInterface,
1284     NoStatStreamImpl_AddRef,
1285     NoStatStreamImpl_Release,
1286     NoStatStreamImpl_Read,
1287     NoStatStreamImpl_Write,
1288     NoStatStreamImpl_Seek,
1289     NoStatStreamImpl_SetSize,
1290     NoStatStreamImpl_CopyTo,
1291     NoStatStreamImpl_Commit,
1292     NoStatStreamImpl_Revert,
1293     NoStatStreamImpl_LockRegion,
1294     NoStatStreamImpl_UnlockRegion,
1295     NoStatStreamImpl_Stat,
1296     NoStatStreamImpl_Clone
1297 };