d3drm: Implement IDirect3DRMMesh_GetGroupColor.
[wine] / dlls / oleaut32 / tests / olepicture.c
1 /*
2  * OLEPICTURE test program
3  *
4  * Copyright 2005 Marcus Meissner
5  * Copyright 2012 Dmitry Timoshkov
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
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 (0)
491 {
492     /* crashes on native */
493     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, NULL);
494 }
495
496     hr = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
497     ok(hr == S_OK, "hr %08x\n", hr);
498
499     type = PICTYPE_NONE;
500     hr = IPicture_get_Type(pict, &type);
501     ok(hr == S_OK, "hr %08x\n", hr);
502     ok(type == PICTYPE_UNINITIALIZED, "type %d\n", type);
503
504     handle = 0xdeadbeef;
505     hr = IPicture_get_Handle(pict, &handle);
506     ok(hr == S_OK, "hr %08x\n", hr);
507     ok(handle == 0, "handle %08x\n", handle);
508
509     IPicture_Release(pict);
510 }
511
512 static void test_apm(void)
513 {
514     OLE_HANDLE handle;
515     LPSTREAM stream;
516     IPicture *pict;
517     HGLOBAL hglob;
518     LPBYTE *data;
519     LONG cxy;
520     BOOL keep;
521     short type;
522
523     hglob = GlobalAlloc (0, sizeof(apmdata));
524     data = GlobalLock(hglob);
525     memcpy(data, apmdata, sizeof(apmdata));
526
527     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
528     ole_check(pOleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
529
530     ole_check(IPicture_get_Handle(pict, &handle));
531     ok(handle != 0, "handle is null\n");
532
533     ole_check(IPicture_get_Type(pict, &type));
534     expect_eq(type, PICTYPE_METAFILE, short, "%d");
535
536     ole_check(IPicture_get_Height(pict, &cxy));
537     expect_eq(cxy,  1667, LONG, "%d");
538
539     ole_check(IPicture_get_Width(pict, &cxy));
540     expect_eq(cxy,  1323, LONG, "%d");
541
542     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
543     todo_wine expect_eq(keep, FALSE, LONG, "%d");
544
545     ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
546     IPicture_Release(pict);
547     IStream_Release(stream);
548 }
549
550 static void test_metafile(void)
551 {
552     LPSTREAM stream;
553     IPicture *pict;
554     HGLOBAL hglob;
555     LPBYTE *data;
556
557     hglob = GlobalAlloc (0, sizeof(metafile));
558     data = GlobalLock(hglob);
559     memcpy(data, metafile, sizeof(metafile));
560
561     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
562     /* Windows does not load simple metafiles */
563     ole_expect(pOleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
564
565     IStream_Release(stream);
566 }
567
568 static void test_enhmetafile(void)
569 {
570     OLE_HANDLE handle;
571     LPSTREAM stream;
572     IPicture *pict;
573     HGLOBAL hglob;
574     LPBYTE *data;
575     LONG cxy;
576     BOOL keep;
577     short type;
578
579     hglob = GlobalAlloc (0, sizeof(enhmetafile));
580     data = GlobalLock(hglob);
581     memcpy(data, enhmetafile, sizeof(enhmetafile));
582
583     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
584     ole_check(pOleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
585
586     ole_check(IPicture_get_Handle(pict, &handle));
587     ok(handle != 0, "handle is null\n");
588
589     ole_check(IPicture_get_Type(pict, &type));
590     expect_eq(type, PICTYPE_ENHMETAFILE, short, "%d");
591
592     ole_check(IPicture_get_Height(pict, &cxy));
593     expect_eq(cxy, -23, LONG, "%d");
594
595     ole_check(IPicture_get_Width(pict, &cxy));
596     expect_eq(cxy, -25, LONG, "%d");
597
598     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
599     todo_wine expect_eq(keep, FALSE, LONG, "%d");
600
601     IPicture_Release(pict);
602     IStream_Release(stream);
603 }
604
605 static void test_Render(void)
606 {
607     IPicture *pic;
608     HRESULT hres;
609     short type;
610     PICTDESC desc;
611     OLE_XSIZE_HIMETRIC pWidth;
612     OLE_YSIZE_HIMETRIC pHeight;
613     COLORREF result, expected;
614     HDC hdc = GetDC(0);
615
616     /* test IPicture::Render return code on uninitialized picture */
617     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
618     hres = IPicture_get_Type(pic, &type);
619     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
620     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
621     /* zero dimensions */
622     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
623     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
624     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
625     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
626     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
627     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
628     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
629     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
630     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
631     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
632     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
633     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
634     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
635     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
636     /* nonzero dimensions, PICTYPE_UNINITIALIZED */
637     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL);
638     ole_expect(hres, S_OK);
639     IPicture_Release(pic);
640
641     desc.cbSizeofstruct = sizeof(PICTDESC);
642     desc.picType = PICTYPE_ICON;
643     desc.u.icon.hicon = LoadIcon(NULL, IDI_APPLICATION);
644     if(!desc.u.icon.hicon){
645         win_skip("LoadIcon failed. Skipping...\n");
646         ReleaseDC(NULL, hdc);
647         return;
648     }
649
650     OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (VOID**)&pic);
651     /* zero dimensions, PICTYPE_ICON */
652     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
653     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
654     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
655     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
656     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
657     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
658     hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
659     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
660     hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
661     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
662     hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
663     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
664     hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
665     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
666
667     /* Check if target size and position is respected */
668     IPicture_get_Width(pic, &pWidth);
669     IPicture_get_Height(pic, &pHeight);
670
671     SetPixelV(hdc, 0, 0, 0x00223344);
672     SetPixelV(hdc, 5, 5, 0x00223344);
673     SetPixelV(hdc, 10, 10, 0x00223344);
674     expected = GetPixel(hdc, 0, 0);
675
676     hres = IPicture_Render(pic, hdc, 1, 1, 9, 9, 0, 0, pWidth, -pHeight, NULL);
677     ole_expect(hres, S_OK);
678
679     if(hres != S_OK) {
680         IPicture_Release(pic);
681         ReleaseDC(NULL, hdc);
682         return;
683     }
684
685     /* Evaluate the rendered Icon */
686     result = GetPixel(hdc, 0, 0);
687     ok(result == expected,
688        "Color at 0,0 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
689     result = GetPixel(hdc, 5, 5);
690     ok(result != expected ||
691         broken(result == expected), /* WinNT 4.0 and older may claim they drew */
692                                     /* the icon, even if they didn't. */
693        "Color at 5,5 should have changed, but still was 0x%06X\n", expected);
694     result = GetPixel(hdc, 10, 10);
695     ok(result == expected,
696        "Color at 10,10 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
697
698     IPicture_Release(pic);
699     ReleaseDC(NULL, hdc);
700 }
701
702 static void test_get_Attributes(void)
703 {
704     IPicture *pic;
705     HRESULT hres;
706     short type;
707     DWORD attr;
708
709     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
710     hres = IPicture_get_Type(pic, &type);
711     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
712     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
713
714     hres = IPicture_get_Attributes(pic, NULL);
715     ole_expect(hres, E_POINTER);
716
717     attr = 0xdeadbeef;
718     hres = IPicture_get_Attributes(pic, &attr);
719     ole_expect(hres, S_OK);
720     ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %d\n", attr);
721
722     IPicture_Release(pic);
723 }
724
725 static void test_get_Handle(void)
726 {
727     IPicture *pic;
728     HRESULT hres;
729
730     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
731
732     hres = IPicture_get_Handle(pic, NULL);
733     ole_expect(hres, E_POINTER);
734
735     IPicture_Release(pic);
736 }
737
738 static void test_get_Type(void)
739 {
740     IPicture *pic;
741     HRESULT hres;
742
743     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
744
745     hres = IPicture_get_Type(pic, NULL);
746     ole_expect(hres, E_POINTER);
747
748     IPicture_Release(pic);
749 }
750
751 static void test_OleLoadPicturePath(void)
752 {
753     static WCHAR emptyW[] = {0};
754
755     IPicture *pic;
756     HRESULT hres;
757     int i;
758     char temp_path[MAX_PATH];
759     char temp_file[MAX_PATH];
760     WCHAR temp_fileW[MAX_PATH + 5] = {'f','i','l','e',':','/','/','/'};
761     HANDLE file;
762     DWORD size;
763     WCHAR *ptr;
764
765     const struct
766     {
767         LPOLESTR szURLorPath;
768         REFIID riid;
769         IPicture **pic;
770     } invalid_parameters[] =
771     {
772         {NULL,  NULL,          NULL},
773         {NULL,  NULL,          &pic},
774         {NULL,  &IID_IPicture, NULL},
775         {NULL,  &IID_IPicture, &pic},
776         {emptyW, NULL,          NULL},
777         {emptyW, &IID_IPicture, NULL},
778     };
779
780     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
781     {
782         pic = (IPicture *)0xdeadbeef;
783         hres = OleLoadPicturePath(invalid_parameters[i].szURLorPath, NULL, 0, 0,
784                                   invalid_parameters[i].riid,
785                                   (void **)invalid_parameters[i].pic);
786         ok(hres == E_INVALIDARG,
787            "[%d] Expected OleLoadPicturePath to return E_INVALIDARG, got 0x%08x\n", i, hres);
788         ok(pic == (IPicture *)0xdeadbeef,
789            "[%d] Expected output pointer to be 0xdeadbeef, got %p\n", i, pic);
790     }
791
792     pic = (IPicture *)0xdeadbeef;
793     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, NULL, (void **)&pic);
794     todo_wine
795     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
796        broken(hres == E_UNEXPECTED) || /* NT4 */
797        broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
798        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
799     ok(pic == NULL,
800        "Expected the output interface pointer to be NULL, got %p\n", pic);
801
802     pic = (IPicture *)0xdeadbeef;
803     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
804     todo_wine
805     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
806        broken(hres == E_UNEXPECTED) || /* NT4 */
807        broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
808        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
809     ok(pic == NULL,
810        "Expected the output interface pointer to be NULL, got %p\n", pic);
811
812     /* Create a local temporary image file for testing. */
813     GetTempPathA(sizeof(temp_path), temp_path);
814     GetTempFileNameA(temp_path, "bmp", 0, temp_file);
815     file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
816                        FILE_ATTRIBUTE_NORMAL, NULL);
817     WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
818     CloseHandle(file);
819
820     MultiByteToWideChar(CP_ACP, 0, temp_file, -1, temp_fileW + 8, sizeof(temp_fileW)/sizeof(WCHAR) - 8);
821
822     /* Try a normal DOS path. */
823     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
824     ok(hres == S_OK ||
825        broken(hres == E_UNEXPECTED), /* NT4 */
826        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
827     if (pic)
828         IPicture_Release(pic);
829
830     /* Try a DOS path with tacked on "file:". */
831     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
832     ok(hres == S_OK ||
833        broken(hres == E_UNEXPECTED), /* NT4 */
834        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
835     if (pic)
836         IPicture_Release(pic);
837
838     DeleteFileA(temp_file);
839
840     /* Try with a nonexistent file. */
841     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
842     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
843        broken(hres == E_UNEXPECTED) || /* NT4 */
844        broken(hres == E_FAIL), /*Win2k */
845        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
846
847     hres = OleLoadPicturePath(temp_fileW, 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     file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
854                        FILE_ATTRIBUTE_NORMAL, NULL);
855     WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
856     CloseHandle(file);
857
858     /* Try a "file:" URL with slash separators. */
859     ptr = temp_fileW + 8;
860     while (*ptr)
861     {
862         if (*ptr == '\\')
863             *ptr = '/';
864         ptr++;
865     }
866
867     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
868     ok(hres == S_OK ||
869        broken(hres == E_UNEXPECTED), /* NT4 */
870        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
871     if (pic)
872         IPicture_Release(pic);
873
874     DeleteFileA(temp_file);
875
876     /* Try with a nonexistent file. */
877     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
878     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
879        broken(hres == E_UNEXPECTED) || /* NT4 */
880        broken(hres == E_FAIL), /* Win2k */
881        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
882 }
883
884 static void test_himetric(void)
885 {
886     static const BYTE bmp_bits[1024];
887     OLE_XSIZE_HIMETRIC cx;
888     OLE_YSIZE_HIMETRIC cy;
889     IPicture *pic;
890     PICTDESC desc;
891     HBITMAP bmp;
892     HRESULT hr;
893     HICON icon;
894     HDC hdc;
895     INT d;
896
897     desc.cbSizeofstruct = sizeof(desc);
898     desc.picType = PICTYPE_BITMAP;
899     desc.u.bmp.hpal = NULL;
900
901     hdc = CreateCompatibleDC(0);
902
903     bmp = CreateBitmap(1.9 * GetDeviceCaps(hdc, LOGPIXELSX),
904                        1.9 * GetDeviceCaps(hdc, LOGPIXELSY), 1, 1, NULL);
905
906     desc.u.bmp.hbitmap = bmp;
907
908     /* size in himetric units reported rounded up to next integer value */
909     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
910     ok(hr == S_OK, "got 0x%08x\n", hr);
911
912     cx = 0;
913     d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSX)), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
914     hr = IPicture_get_Width(pic, &cx);
915     ok(hr == S_OK, "got 0x%08x\n", hr);
916     ok(cx == d, "got %d, expected %d\n", cx, d);
917
918     cy = 0;
919     d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSY)), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
920     hr = IPicture_get_Height(pic, &cy);
921     ok(hr == S_OK, "got 0x%08x\n", hr);
922     ok(cy == d, "got %d, expected %d\n", cy, d);
923
924     DeleteObject(bmp);
925     IPicture_Release(pic);
926
927     /* same thing with icon */
928     icon = CreateIcon(NULL, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
929                       1, 1, bmp_bits, bmp_bits);
930     ok(icon != NULL, "failed to create icon\n");
931
932     desc.picType = PICTYPE_ICON;
933     desc.u.icon.hicon = icon;
934
935     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
936     ok(hr == S_OK, "got 0x%08x\n", hr);
937
938     cx = 0;
939     d = MulDiv(GetSystemMetrics(SM_CXICON), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
940     hr = IPicture_get_Width(pic, &cx);
941     ok(hr == S_OK, "got 0x%08x\n", hr);
942     ok(cx == d, "got %d, expected %d\n", cx, d);
943
944     cy = 0;
945     d = MulDiv(GetSystemMetrics(SM_CYICON), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
946     hr = IPicture_get_Height(pic, &cy);
947     ok(hr == S_OK, "got 0x%08x\n", hr);
948     ok(cy == d, "got %d, expected %d\n", cy, d);
949
950     IPicture_Release(pic);
951     DestroyIcon(icon);
952
953     DeleteDC(hdc);
954 }
955
956 static void test_load_save_bmp(void)
957 {
958     IPicture *pic;
959     PICTDESC desc;
960     short type;
961     OLE_HANDLE handle;
962     HGLOBAL hmem;
963     DWORD *mem;
964     IPersistStream *src_stream;
965     IStream *dst_stream;
966     HRESULT hr;
967
968     desc.cbSizeofstruct = sizeof(desc);
969     desc.picType = PICTYPE_BITMAP;
970     desc.u.bmp.hpal = 0;
971     desc.u.bmp.hbitmap = CreateBitmap(1, 1, 1, 1, NULL);
972     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
973     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
974
975     type = -1;
976     hr = IPicture_get_Type(pic, &type);
977     ok(hr == S_OK,"get_Type error %#8x\n", hr);
978     ok(type == PICTYPE_BITMAP,"expected picture type PICTYPE_BITMAP, got %d\n", type);
979
980     hr = IPicture_get_Handle(pic, &handle);
981     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
982     ok(IntToPtr(handle) == desc.u.bmp.hbitmap, "get_Handle returned wrong handle %#x\n", handle);
983
984     hmem = GlobalAlloc(GMEM_ZEROINIT, 4096);
985     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
986     ok(hr == S_OK, "createstreamonhglobal error %#x\n", hr);
987
988     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
989     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
990
991     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
992     ok(hr == S_OK, "Save error %#x\n", hr);
993
994     IPersistStream_Release(src_stream);
995     IStream_Release(dst_stream);
996
997     mem = GlobalLock(hmem);
998     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
999     ok(mem[1] == 66, "expected stream size 66, got %u\n", mem[1]);
1000     ok(!memcmp(&mem[2], "BM", 2), "got wrong bmp header %04x\n", mem[2]);
1001
1002     GlobalUnlock(hmem);
1003     GlobalFree(hmem);
1004
1005     DeleteObject(desc.u.bmp.hbitmap);
1006     IPicture_Release(pic);
1007 }
1008
1009 static void test_load_save_icon(void)
1010 {
1011     IPicture *pic;
1012     PICTDESC desc;
1013     short type;
1014     OLE_HANDLE handle;
1015     HGLOBAL hmem;
1016     DWORD *mem;
1017     IPersistStream *src_stream;
1018     IStream *dst_stream;
1019     HRESULT hr;
1020
1021     desc.cbSizeofstruct = sizeof(desc);
1022     desc.picType = PICTYPE_ICON;
1023     desc.u.icon.hicon = LoadIcon(0, IDI_APPLICATION);
1024     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1025     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
1026
1027     type = -1;
1028     hr = IPicture_get_Type(pic, &type);
1029     ok(hr == S_OK,"get_Type error %#8x\n", hr);
1030     ok(type == PICTYPE_ICON,"expected picture type PICTYPE_ICON, got %d\n", type);
1031
1032     hr = IPicture_get_Handle(pic, &handle);
1033     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1034     ok(IntToPtr(handle) == desc.u.icon.hicon, "get_Handle returned wrong handle %#x\n", handle);
1035
1036     hmem = GlobalAlloc(GMEM_ZEROINIT, 8192);
1037     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
1038     ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
1039
1040     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
1041     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1042
1043     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
1044     ok(hr == S_OK, "Saveerror %#x\n", hr);
1045
1046     IPersistStream_Release(src_stream);
1047     IStream_Release(dst_stream);
1048
1049     mem = GlobalLock(hmem);
1050     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
1051 todo_wine
1052     ok(mem[1] == 766, "expected stream size 766, got %u\n", mem[1]);
1053     ok(mem[2] == 0x00010000, "got wrong icon header %04x\n", mem[2]);
1054
1055     GlobalUnlock(hmem);
1056     GlobalFree(hmem);
1057
1058     DeleteObject(desc.u.bmp.hbitmap);
1059     IPicture_Release(pic);
1060 }
1061
1062 START_TEST(olepicture)
1063 {
1064     hOleaut32 = GetModuleHandleA("oleaut32.dll");
1065     pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
1066     pOleLoadPictureEx = (void*)GetProcAddress(hOleaut32, "OleLoadPictureEx");
1067     if (!pOleLoadPicture)
1068     {
1069         win_skip("OleLoadPicture is not available\n");
1070         return;
1071     }
1072
1073     /* Test regular 1x1 pixel images of gif, jpg, bmp type */
1074     test_pic(gifimage, sizeof(gifimage));
1075     test_pic(jpgimage, sizeof(jpgimage));
1076     test_pic(bmpimage, sizeof(bmpimage));
1077     test_pic(gif4pixel, sizeof(gif4pixel));
1078     /* FIXME: No PNG support in Windows... */
1079     if (0) test_pic(pngimage, sizeof(pngimage));
1080     test_empty_image();
1081     test_empty_image_2();
1082     if (pOleLoadPictureEx)
1083     {
1084         test_apm();
1085         test_metafile();
1086         test_enhmetafile();
1087     }
1088     else
1089         win_skip("OleLoadPictureEx is not available\n");
1090     test_Invoke();
1091     test_OleCreatePictureIndirect();
1092     test_Render();
1093     test_get_Attributes();
1094     test_get_Handle();
1095     test_get_Type();
1096     test_OleLoadPicturePath();
1097     test_himetric();
1098     test_load_save_bmp();
1099     test_load_save_icon();
1100 }
1101
1102
1103 /* Helper functions only ... */
1104
1105
1106 static inline NoStatStreamImpl *impl_from_IStream(IStream *iface)
1107 {
1108   return CONTAINING_RECORD(iface, NoStatStreamImpl, IStream_iface);
1109 }
1110
1111 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
1112 {
1113   GlobalFree(This->supportHandle);
1114   This->supportHandle=0;
1115   HeapFree(GetProcessHeap(), 0, This);
1116 }
1117
1118 static ULONG WINAPI NoStatStreamImpl_AddRef(
1119                 IStream* iface)
1120 {
1121   NoStatStreamImpl* const This = impl_from_IStream(iface);
1122   return InterlockedIncrement(&This->ref);
1123 }
1124
1125 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
1126                   IStream*     iface,
1127                   REFIID         riid,        /* [in] */
1128                   void**         ppvObject)   /* [iid_is][out] */
1129 {
1130   NoStatStreamImpl* const This = impl_from_IStream(iface);
1131   if (ppvObject==0) return E_INVALIDARG;
1132   *ppvObject = 0;
1133   if (IsEqualIID(&IID_IUnknown, riid))
1134   {
1135     *ppvObject = This;
1136   }
1137   else if (IsEqualIID(&IID_IStream, riid))
1138   {
1139     *ppvObject = This;
1140   }
1141
1142   if ((*ppvObject)==0)
1143     return E_NOINTERFACE;
1144   NoStatStreamImpl_AddRef(iface);
1145   return S_OK;
1146 }
1147
1148 static ULONG WINAPI NoStatStreamImpl_Release(
1149                 IStream* iface)
1150 {
1151   NoStatStreamImpl* const This = impl_from_IStream(iface);
1152   ULONG newRef = InterlockedDecrement(&This->ref);
1153   if (newRef==0)
1154     NoStatStreamImpl_Destroy(This);
1155   return newRef;
1156 }
1157
1158 static HRESULT WINAPI NoStatStreamImpl_Read(
1159                   IStream*     iface,
1160                   void*          pv,        /* [length_is][size_is][out] */
1161                   ULONG          cb,        /* [in] */
1162                   ULONG*         pcbRead)   /* [out] */
1163 {
1164   NoStatStreamImpl* const This = impl_from_IStream(iface);
1165   void* supportBuffer;
1166   ULONG bytesReadBuffer;
1167   ULONG bytesToReadFromBuffer;
1168
1169   if (pcbRead==0)
1170     pcbRead = &bytesReadBuffer;
1171   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
1172   supportBuffer = GlobalLock(This->supportHandle);
1173   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
1174   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
1175   *pcbRead = bytesToReadFromBuffer;
1176   GlobalUnlock(This->supportHandle);
1177   if(*pcbRead == cb)
1178     return S_OK;
1179   return S_FALSE;
1180 }
1181
1182 static HRESULT WINAPI NoStatStreamImpl_Write(
1183                   IStream*     iface,
1184                   const void*    pv,          /* [size_is][in] */
1185                   ULONG          cb,          /* [in] */
1186                   ULONG*         pcbWritten)  /* [out] */
1187 {
1188   NoStatStreamImpl* const This = impl_from_IStream(iface);
1189   void*          supportBuffer;
1190   ULARGE_INTEGER newSize;
1191   ULONG          bytesWritten = 0;
1192
1193   if (pcbWritten == 0)
1194     pcbWritten = &bytesWritten;
1195   if (cb == 0)
1196     return S_OK;
1197   newSize.u.HighPart = 0;
1198   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
1199   if (newSize.u.LowPart > This->streamSize.u.LowPart)
1200    IStream_SetSize(iface, newSize);
1201
1202   supportBuffer = GlobalLock(This->supportHandle);
1203   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
1204   This->currentPosition.u.LowPart+=cb;
1205   *pcbWritten = cb;
1206   GlobalUnlock(This->supportHandle);
1207   return S_OK;
1208 }
1209
1210 static HRESULT WINAPI NoStatStreamImpl_Seek(
1211                   IStream*      iface,
1212                   LARGE_INTEGER   dlibMove,         /* [in] */
1213                   DWORD           dwOrigin,         /* [in] */
1214                   ULARGE_INTEGER* plibNewPosition) /* [out] */
1215 {
1216   NoStatStreamImpl* const This = impl_from_IStream(iface);
1217   ULARGE_INTEGER newPosition;
1218   switch (dwOrigin)
1219   {
1220     case STREAM_SEEK_SET:
1221       newPosition.u.HighPart = 0;
1222       newPosition.u.LowPart = 0;
1223       break;
1224     case STREAM_SEEK_CUR:
1225       newPosition = This->currentPosition;
1226       break;
1227     case STREAM_SEEK_END:
1228       newPosition = This->streamSize;
1229       break;
1230     default:
1231       return STG_E_INVALIDFUNCTION;
1232   }
1233   if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
1234       return STG_E_INVALIDFUNCTION;
1235   newPosition.QuadPart += dlibMove.QuadPart;
1236   if (plibNewPosition) *plibNewPosition = newPosition;
1237   This->currentPosition = newPosition;
1238   return S_OK;
1239 }
1240
1241 static HRESULT WINAPI NoStatStreamImpl_SetSize(
1242                                      IStream*      iface,
1243                                      ULARGE_INTEGER  libNewSize)   /* [in] */
1244 {
1245   NoStatStreamImpl* const This = impl_from_IStream(iface);
1246   HGLOBAL supportHandle;
1247   if (libNewSize.u.HighPart != 0)
1248     return STG_E_INVALIDFUNCTION;
1249   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
1250     return S_OK;
1251   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
1252   if (supportHandle == 0)
1253     return STG_E_MEDIUMFULL;
1254   This->supportHandle = supportHandle;
1255   This->streamSize.u.LowPart = libNewSize.u.LowPart;
1256   return S_OK;
1257 }
1258
1259 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
1260                                     IStream*      iface,
1261                                     IStream*      pstm,         /* [unique][in] */
1262                                     ULARGE_INTEGER  cb,           /* [in] */
1263                                     ULARGE_INTEGER* pcbRead,      /* [out] */
1264                                     ULARGE_INTEGER* pcbWritten)   /* [out] */
1265 {
1266   HRESULT        hr = S_OK;
1267   BYTE           tmpBuffer[128];
1268   ULONG          bytesRead, bytesWritten, copySize;
1269   ULARGE_INTEGER totalBytesRead;
1270   ULARGE_INTEGER totalBytesWritten;
1271
1272   if ( pstm == 0 )
1273     return STG_E_INVALIDPOINTER;
1274   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
1275   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
1276
1277   while ( cb.u.LowPart > 0 )
1278   {
1279     if ( cb.u.LowPart >= 128 )
1280       copySize = 128;
1281     else
1282       copySize = cb.u.LowPart;
1283     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1284     totalBytesRead.u.LowPart += bytesRead;
1285     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1286     totalBytesWritten.u.LowPart += bytesWritten;
1287     if (bytesRead != bytesWritten)
1288     {
1289       hr = STG_E_MEDIUMFULL;
1290       break;
1291     }
1292     if (bytesRead!=copySize)
1293       cb.u.LowPart = 0;
1294     else
1295       cb.u.LowPart -= bytesRead;
1296   }
1297   if (pcbRead)
1298   {
1299     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
1300     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
1301   }
1302
1303   if (pcbWritten)
1304   {
1305     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
1306     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
1307   }
1308   return hr;
1309 }
1310
1311 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
1312 {
1313   return S_OK;
1314 }
1315 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
1316
1317 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
1318                   IStream*       iface,
1319                   ULARGE_INTEGER libOffset,   /* [in] */
1320                   ULARGE_INTEGER cb,          /* [in] */
1321                   DWORD          dwLockType)  /* [in] */
1322 {
1323   return S_OK;
1324 }
1325
1326 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
1327                   IStream*       iface,
1328                   ULARGE_INTEGER libOffset,   /* [in] */
1329                   ULARGE_INTEGER cb,          /* [in] */
1330                   DWORD          dwLockType)  /* [in] */
1331 {
1332   return S_OK;
1333 }
1334
1335 static HRESULT WINAPI NoStatStreamImpl_Stat(
1336                   IStream*     iface,
1337                   STATSTG*     pstatstg,     /* [out] */
1338                   DWORD        grfStatFlag)  /* [in] */
1339 {
1340   return E_NOTIMPL;
1341 }
1342
1343 static HRESULT WINAPI NoStatStreamImpl_Clone(
1344                   IStream*     iface,
1345                   IStream**    ppstm) /* [out] */
1346 {
1347   return E_NOTIMPL;
1348 }
1349 static const IStreamVtbl NoStatStreamImpl_Vtbl;
1350
1351 /*
1352     Build an object that implements IStream, without IStream_Stat capabilities.
1353     Receives a memory handle with data buffer. If memory handle is non-null,
1354     it is assumed to be unlocked, otherwise an internal memory handle is allocated.
1355     In any case the object takes ownership of memory handle and will free it on
1356     object release.
1357  */
1358 static IStream* NoStatStream_Construct(HGLOBAL hGlobal)
1359 {
1360   NoStatStreamImpl* newStream;
1361
1362   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
1363   if (newStream!=0)
1364   {
1365     newStream->IStream_iface.lpVtbl = &NoStatStreamImpl_Vtbl;
1366     newStream->ref    = 1;
1367     newStream->supportHandle = hGlobal;
1368
1369     if (!newStream->supportHandle)
1370       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
1371                                              GMEM_SHARE, 0);
1372     newStream->currentPosition.u.HighPart = 0;
1373     newStream->currentPosition.u.LowPart = 0;
1374     newStream->streamSize.u.HighPart = 0;
1375     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
1376   }
1377   return &newStream->IStream_iface;
1378 }
1379
1380
1381 static const IStreamVtbl NoStatStreamImpl_Vtbl =
1382 {
1383     NoStatStreamImpl_QueryInterface,
1384     NoStatStreamImpl_AddRef,
1385     NoStatStreamImpl_Release,
1386     NoStatStreamImpl_Read,
1387     NoStatStreamImpl_Write,
1388     NoStatStreamImpl_Seek,
1389     NoStatStreamImpl_SetSize,
1390     NoStatStreamImpl_CopyTo,
1391     NoStatStreamImpl_Commit,
1392     NoStatStreamImpl_Revert,
1393     NoStatStreamImpl_LockRegion,
1394     NoStatStreamImpl_UnlockRegion,
1395     NoStatStreamImpl_Stat,
1396     NoStatStreamImpl_Clone
1397 };