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