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