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