1 /*
2  * OLEPICTURE test program
3  *
4  * Copyright 2005 Marcus Meissner
5  * Copyright 2012 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <math.h>
25 #include <float.h>
26 
27 #define COBJMACROS
28 #define CONST_VTABLE
29 #ifndef __REACTOS__
30 #define NONAMELESSUNION
31 #endif
32 
33 #include "wine/test.h"
34 #include <windef.h>
35 #include <winbase.h>
36 #include <winuser.h>
37 #include <wingdi.h>
38 #include <winnls.h>
39 #include <winerror.h>
40 #include <winnt.h>
41 
42 #include <urlmon.h>
43 #include <wtypes.h>
44 #include <olectl.h>
45 #include <objidl.h>
46 
47 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
48 
49 #define ole_expect(expr, expect) { \
50     HRESULT r = expr; \
51     ok(r == (expect), #expr " returned %x, expected %s (%x)\n", r, #expect, expect); \
52 }
53 
54 #define ole_check(expr) ole_expect(expr, S_OK);
55 
56 static HMODULE hOleaut32;
57 
58 static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);
59 static HRESULT (WINAPI *pOleLoadPictureEx)(LPSTREAM,LONG,BOOL,REFIID,DWORD,DWORD,DWORD,LPVOID*);
60 
61 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
62 
63 /* 1x1 pixel gif */
64 static const unsigned char gifimage[35] = {
65 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
66 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
67 0x01,0x00,0x3b
68 };
69 
70 /* 1x1 pixel jpg */
71 static const unsigned char jpgimage[285] = {
72 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
73 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
74 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
75 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
76 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
77 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
78 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
79 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
80 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
81 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
82 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
83 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
84 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
85 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
86 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
87 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
88 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
89 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
90 };
91 
92 /* 1x1 pixel png */
93 static const unsigned char pngimage[285] = {
94 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
95 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
96 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
97 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
98 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
99 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
100 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
101 };
102 
103 /* 1bpp BI_RGB 1x1 pixel bmp */
104 static const unsigned char bmpimage[66] = {
105 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
106 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
107 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
108 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
109 0x00,0x00
110 };
111 
112 /* 8bpp BI_RLE8 1x1 pixel bmp */
113 static const unsigned char bmpimage_rle8[] = {
114 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
115 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x01,0x00,
116 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
117 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x01,
118 0x00,0x00
119 };
120 
121 /* 2x2 pixel gif */
122 static const unsigned char gif4pixel[42] = {
123 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
124 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
125 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
126 };
127 
128 /* APM with an empty metafile with some padding zeros - looks like under Window the
129  * metafile data should be at least 20 bytes */
130 static const unsigned char apmdata[] = {
131 0xd7,0xcd,0xc6,0x9a, 0x00,0x00,0x00,0x00, 0x00,0x00,0xee,0x02, 0xb1,0x03,0xa0,0x05,
132 0x00,0x00,0x00,0x00, 0xee,0x53,0x01,0x00, 0x09,0x00,0x00,0x03, 0x13,0x00,0x00,0x00,
133 0x01,0x00,0x05,0x00, 0x00,0x00,0x00,0x00, 0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
134 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
135 };
136 
137 /* MF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
138 static const unsigned char metafile[] = {
139     0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
140     0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
141     0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
142     0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
143     0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
144     0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
145     0x00, 0x00
146 };
147 
148 /* EMF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
149 static const unsigned char enhmetafile[] = {
150     0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
151     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
153     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154     0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
155     0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
156     0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
157     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159     0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
160     0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
161     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162     0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
163     0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
164     0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
165     0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
167     0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
168     0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
169     0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
170     0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
171     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172     0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
173     0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
174     0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
175     0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
176     0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
177     0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
178     0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
179     0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
180     0x14, 0x00, 0x00, 0x00
181 };
182 
183 static HBITMAP stock_bm;
184 
185 static HDC create_render_dc( void )
186 {
187     HDC dc = CreateCompatibleDC( NULL );
188     BITMAPINFO info = {{sizeof(info.bmiHeader), 100, 100, 1, 32, BI_RGB }};
189     void *bits;
190     HBITMAP dib = CreateDIBSection( NULL, &info, DIB_RGB_COLORS, &bits, NULL, 0 );
191 
192     stock_bm = SelectObject( dc, dib );
193     return dc;
194 }
195 
196 static void delete_render_dc( HDC dc )
197 {
198     HBITMAP dib = SelectObject( dc, stock_bm );
199     DeleteObject( dib );
200     DeleteDC( dc );
201 }
202 
203 typedef struct NoStatStreamImpl
204 {
205 	IStream			IStream_iface;
206 	LONG			ref;
207 
208 	HGLOBAL			supportHandle;
209 	ULARGE_INTEGER		streamSize;
210 	ULARGE_INTEGER		currentPosition;
211 } NoStatStreamImpl;
212 
213 static IStream* NoStatStream_Construct(HGLOBAL hGlobal);
214 
215 static void
216 test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
217 {
218 	IPicture*	pic = NULL;
219 	HRESULT		hres;
220 	LPVOID		pvObj = NULL;
221 	OLE_HANDLE	handle, hPal;
222 	OLE_XSIZE_HIMETRIC	width;
223 	OLE_YSIZE_HIMETRIC	height;
224 	short		type;
225 	DWORD		attr;
226 	ULONG		res;
227 
228 	pvObj = NULL;
229 	hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
230 	pic = pvObj;
231 
232 	ok(hres == S_OK,"OLP (NULL,..) does not return 0, but 0x%08x\n",hres);
233 	ok(pic != NULL,"OLP (NULL,..) returns NULL, instead of !NULL\n");
234 	if (pic == NULL)
235 		return;
236 
237 	pvObj = NULL;
238 	hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);
239 
240 	ok(hres == S_OK,"IPicture_QI does not return S_OK, but 0x%08x\n", hres);
241 	ok(pvObj != NULL,"IPicture_QI does return NULL, instead of a ptr\n");
242 
243 	IPicture_Release ((IPicture*)pvObj);
244 
245 	handle = 0;
246 	hres = IPicture_get_Handle (pic, &handle);
247 	ok(hres == S_OK,"IPicture_get_Handle does not return S_OK, but 0x%08x\n", hres);
248 	ok(handle != 0, "IPicture_get_Handle returns a NULL handle, but it should be non NULL\n");
249 
250         if (handle)
251         {
252             BITMAP bmp;
253             GetObjectA(UlongToHandle(handle), sizeof(BITMAP), &bmp);
254             ok(bmp.bmBits != 0, "not a dib\n");
255         }
256 
257 	width = 0;
258 	hres = IPicture_get_Width (pic, &width);
259 	ok(hres == S_OK,"IPicture_get_Width does not return S_OK, but 0x%08x\n", hres);
260 	ok(width != 0, "IPicture_get_Width returns 0, but it should not be 0.\n");
261 
262 	height = 0;
263 	hres = IPicture_get_Height (pic, &height);
264 	ok(hres == S_OK,"IPicture_get_Height does not return S_OK, but 0x%08x\n", hres);
265 	ok(height != 0, "IPicture_get_Height returns 0, but it should not be 0.\n");
266 
267 	type = 0;
268 	hres = IPicture_get_Type (pic, &type);
269 	ok(hres == S_OK,"IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
270 	ok(type == PICTYPE_BITMAP, "IPicture_get_Type returns %d, but it should be PICTYPE_BITMAP(%d).\n", type, PICTYPE_BITMAP);
271 
272 	attr = 0;
273 	hres = IPicture_get_Attributes (pic, &attr);
274 	ok(hres == S_OK,"IPicture_get_Attributes does not return S_OK, but 0x%08x\n", hres);
275 	ok(attr == 0, "IPicture_get_Attributes returns %d, but it should be 0.\n", attr);
276 
277 	hPal = 0;
278 	hres = IPicture_get_hPal (pic, &hPal);
279 	ok(hres == S_OK,"IPicture_get_hPal does not return S_OK, but 0x%08x\n", hres);
280 	/* a single pixel b/w image has no palette */
281 	ok(hPal == 0, "IPicture_get_hPal returns %d, but it should be 0.\n", hPal);
282 
283 	res = IPicture_Release (pic);
284 	ok (res == 0, "refcount after release is %d, but should be 0?\n", res);
285 }
286 
287 static void
288 test_pic(const unsigned char *imgdata, unsigned int imgsize)
289 {
290 	LPSTREAM 	stream;
291 	HGLOBAL		hglob;
292 	LPBYTE		data;
293 	HRESULT		hres;
294 	LARGE_INTEGER	seekto;
295 	ULARGE_INTEGER	newpos1;
296 	DWORD * 	header;
297 	unsigned int 	i,j;
298 
299 	/* Let the fun begin */
300 	hglob = GlobalAlloc (0, imgsize);
301 	data = GlobalLock (hglob);
302 	memcpy(data, 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 = NoStatStream_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 	for (i = 1; i <= 8; i++) {
322 		/* more fun!!! */
323 		hglob = GlobalAlloc (0, imgsize + i * (2 * sizeof(DWORD)));
324 		data = GlobalLock (hglob);
325 		header = (DWORD *)data;
326 
327 		/* multiple copies of header */
328 		memcpy(data,"lt\0\0",4);
329 		header[1] = imgsize;
330 		for (j = 2; j <= i; j++) {
331 			memcpy(&(header[2 * (j - 1)]), header, 2 * sizeof(DWORD));
332 		}
333 		memcpy(data + i * (2 * sizeof(DWORD)), imgdata, imgsize);
334 		GlobalUnlock(hglob); data = NULL;
335 
336 		hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
337 		ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
338 
339 		memset(&seekto,0,sizeof(seekto));
340 		hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
341 		ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
342 		test_pic_with_stream(stream, imgsize);
343 
344 		IStream_Release(stream);
345 
346 		/* again with Non Statable and Non Seekable stream */
347 		stream = NoStatStream_Construct(hglob);
348 		hglob = 0;  /* Non-statable impl always deletes on release */
349 		test_pic_with_stream(stream, 0);
350 
351 		IStream_Release(stream);
352 	}
353 }
354 
355 static void test_empty_image(void) {
356 	LPBYTE		data;
357 	LPSTREAM	stream;
358 	IPicture*	pic = NULL;
359 	HRESULT		hres;
360 	LPVOID		pvObj = NULL;
361 	HGLOBAL		hglob;
362 	OLE_HANDLE	handle;
363 	ULARGE_INTEGER	newpos1;
364 	LARGE_INTEGER	seekto;
365 	short		type;
366 	DWORD		attr;
367 
368 	/* Empty image. Happens occasionally in VB programs. */
369 	hglob = GlobalAlloc (0, 8);
370 	data = GlobalLock (hglob);
371 	memcpy(data,"lt\0\0",4);
372 	((DWORD*)data)[1] = 0;
373 	hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
374 	ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
375 
376 	memset(&seekto,0,sizeof(seekto));
377 	hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
378 	ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
379 
380 	pvObj = NULL;
381 	hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
382 	pic = pvObj;
383 	ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
384 	ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
385 
386 	hres = IPicture_get_Type (pic, &type);
387 	ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
388 	ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
389 
390 	attr = 0xdeadbeef;
391 	hres = IPicture_get_Attributes (pic, &attr);
392 	ok (hres == S_OK,"empty picture get attributes failed with hres 0x%08x\n", hres);
393 	ok (attr == 0,"attr is %d, but should be 0\n", attr);
394 
395 	hres = IPicture_get_Handle (pic, &handle);
396 	ok (hres == S_OK,"empty picture get handle failed with hres 0x%08x\n", hres);
397 	ok (handle == 0, "empty picture get handle did not return 0, but 0x%08x\n", handle);
398 	IPicture_Release (pic);
399 	IStream_Release (stream);
400 }
401 
402 static void test_empty_image_2(void) {
403 	LPBYTE		data;
404 	LPSTREAM	stream;
405 	IPicture*	pic = NULL;
406 	HRESULT		hres;
407 	LPVOID		pvObj = NULL;
408 	HGLOBAL		hglob;
409 	ULARGE_INTEGER	newpos1;
410 	LARGE_INTEGER	seekto;
411 	short		type;
412 
413 	/* Empty image at random stream position. */
414 	hglob = GlobalAlloc (0, 200);
415 	data = GlobalLock (hglob);
416 	data += 42;
417 	memcpy(data,"lt\0\0",4);
418 	((DWORD*)data)[1] = 0;
419 	hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
420 	ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
421 
422 	memset(&seekto,0,sizeof(seekto));
423 	seekto.u.LowPart = 42;
424 	hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
425 	ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
426 
427 	pvObj = NULL;
428 	hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
429 	pic = pvObj;
430 	ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
431 	ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
432 
433 	hres = IPicture_get_Type (pic, &type);
434 	ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
435 	ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
436 
437 	IPicture_Release (pic);
438 	IStream_Release (stream);
439 }
440 
441 static void test_Invoke(void)
442 {
443     IPictureDisp *picdisp;
444     HRESULT hr;
445     VARIANTARG vararg, args[10];
446     DISPPARAMS dispparams;
447     VARIANT varresult;
448     IStream *stream;
449     HGLOBAL hglob;
450     void *data;
451     HDC hdc;
452     int i;
453 
454     hglob = GlobalAlloc (0, sizeof(gifimage));
455     data = GlobalLock(hglob);
456     memcpy(data, gifimage, sizeof(gifimage));
457     GlobalUnlock(hglob);
458 
459     hr = CreateStreamOnHGlobal (hglob, FALSE, &stream);
460     ok_ole_success(hr, "CreateStreamOnHGlobal");
461 
462     hr = pOleLoadPicture(stream, sizeof(gifimage), TRUE, &IID_IPictureDisp, (void **)&picdisp);
463     IStream_Release(stream);
464     GlobalFree(hglob);
465     ok_ole_success(hr, "OleLoadPicture");
466 
467     V_VT(&vararg) = VT_BOOL;
468     V_BOOL(&vararg) = VARIANT_FALSE;
469     dispparams.cNamedArgs = 0;
470     dispparams.rgdispidNamedArgs = NULL;
471     dispparams.cArgs = 1;
472     dispparams.rgvarg = &vararg;
473     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IPictureDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
474     ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
475     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IUnknown, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
476     ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
477 
478     dispparams.cArgs = 0;
479     dispparams.rgvarg = NULL;
480     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
481     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
482 
483     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, NULL, NULL, NULL, NULL);
484     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
485 
486     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, NULL, NULL, NULL);
487     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
488 
489     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
490     ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
491 
492     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
493     ok_ole_success(hr, "IPictureDisp_Invoke");
494     ok(V_VT(&varresult) == VT_I4, "V_VT(&varresult) should have been VT_UINT instead of %d\n", V_VT(&varresult));
495 
496     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
497     ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
498 
499     hr = IPictureDisp_Invoke(picdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
500     ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
501 
502     dispparams.cArgs = 1;
503     dispparams.rgvarg = &vararg;
504     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
505     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
506 
507     dispparams.cArgs = 1;
508     dispparams.rgvarg = &vararg;
509     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
510     ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
511 
512     /* DISPID_PICT_RENDER */
513     hdc = create_render_dc();
514 
515     for (i = 0; i < sizeof(args)/sizeof(args[0]); i++)
516         V_VT(&args[i]) = VT_I4;
517 
518     V_I4(&args[0]) = 0;
519     V_I4(&args[1]) = 10;
520     V_I4(&args[2]) = 10;
521     V_I4(&args[3]) = 0;
522     V_I4(&args[4]) = 0;
523     V_I4(&args[5]) = 10;
524     V_I4(&args[6]) = 10;
525     V_I4(&args[7]) = 0;
526     V_I4(&args[8]) = 0;
527     V_I4(&args[9]) = HandleToLong(hdc);
528 
529     dispparams.rgvarg = args;
530     dispparams.rgdispidNamedArgs = NULL;
531     dispparams.cArgs = 10;
532     dispparams.cNamedArgs = 0;
533 
534     V_VT(&varresult) = VT_EMPTY;
535     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
536     ok(hr == S_OK, "got 0x%08x\n", hr);
537 
538     /* Try with one argument set to VT_I2, it'd still work if coerced. */
539     V_VT(&args[3]) = VT_I2;
540     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
541     ok(hr == DISP_E_TYPEMISMATCH, "got 0x%08x\n", hr);
542     V_VT(&args[3]) = VT_I4;
543 
544     /* Wrong argument count */
545     dispparams.cArgs = 9;
546     hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
547     ok(hr == DISP_E_BADPARAMCOUNT, "got 0x%08x\n", hr);
548 
549     delete_render_dc(hdc);
550     IPictureDisp_Release(picdisp);
551 }
552 
553 static void test_OleCreatePictureIndirect(void)
554 {
555     OLE_HANDLE handle;
556     IPicture *pict;
557     HRESULT hr;
558     short type;
559 
560 if (0)
561 {
562     /* crashes on native */
563     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, NULL);
564 }
565 
566     hr = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
567     ok(hr == S_OK, "hr %08x\n", hr);
568 
569     type = PICTYPE_NONE;
570     hr = IPicture_get_Type(pict, &type);
571     ok(hr == S_OK, "hr %08x\n", hr);
572     ok(type == PICTYPE_UNINITIALIZED, "type %d\n", type);
573 
574     handle = 0xdeadbeef;
575     hr = IPicture_get_Handle(pict, &handle);
576     ok(hr == S_OK, "hr %08x\n", hr);
577     ok(handle == 0, "handle %08x\n", handle);
578 
579     IPicture_Release(pict);
580 }
581 
582 static void test_apm(void)
583 {
584     OLE_HANDLE handle;
585     LPSTREAM stream;
586     IPicture *pict;
587     HGLOBAL hglob;
588     LPBYTE *data;
589     LONG cxy;
590     BOOL keep;
591     short type;
592 
593     hglob = GlobalAlloc (0, sizeof(apmdata));
594     data = GlobalLock(hglob);
595     memcpy(data, apmdata, sizeof(apmdata));
596 
597     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
598     ole_check(pOleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
599 
600     ole_check(IPicture_get_Handle(pict, &handle));
601     ok(handle != 0, "handle is null\n");
602 
603     ole_check(IPicture_get_Type(pict, &type));
604     expect_eq(type, PICTYPE_METAFILE, short, "%d");
605 
606     ole_check(IPicture_get_Height(pict, &cxy));
607     expect_eq(cxy,  1667, LONG, "%d");
608 
609     ole_check(IPicture_get_Width(pict, &cxy));
610     expect_eq(cxy,  1323, LONG, "%d");
611 
612     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
613     todo_wine expect_eq(keep, FALSE, LONG, "%d");
614 
615     ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
616     IPicture_Release(pict);
617     IStream_Release(stream);
618 }
619 
620 static void test_metafile(void)
621 {
622     LPSTREAM stream;
623     IPicture *pict;
624     HGLOBAL hglob;
625     LPBYTE *data;
626 
627     hglob = GlobalAlloc (0, sizeof(metafile));
628     data = GlobalLock(hglob);
629     memcpy(data, metafile, sizeof(metafile));
630 
631     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
632     /* Windows does not load simple metafiles */
633     ole_expect(pOleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
634 
635     IStream_Release(stream);
636 }
637 
638 static void test_enhmetafile(void)
639 {
640     OLE_HANDLE handle;
641     LPSTREAM stream;
642     IPicture *pict;
643     HGLOBAL hglob;
644     LPBYTE *data;
645     LONG cxy;
646     BOOL keep;
647     short type;
648 
649     hglob = GlobalAlloc (0, sizeof(enhmetafile));
650     data = GlobalLock(hglob);
651     memcpy(data, enhmetafile, sizeof(enhmetafile));
652 
653     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
654     ole_check(pOleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
655 
656     ole_check(IPicture_get_Handle(pict, &handle));
657     ok(handle != 0, "handle is null\n");
658 
659     ole_check(IPicture_get_Type(pict, &type));
660     expect_eq(type, PICTYPE_ENHMETAFILE, short, "%d");
661 
662     ole_check(IPicture_get_Height(pict, &cxy));
663     expect_eq(cxy, -23, LONG, "%d");
664 
665     ole_check(IPicture_get_Width(pict, &cxy));
666     expect_eq(cxy, -25, LONG, "%d");
667 
668     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
669     todo_wine expect_eq(keep, FALSE, LONG, "%d");
670 
671     IPicture_Release(pict);
672     IStream_Release(stream);
673 }
674 
675 static HRESULT picture_render(IPicture *iface, HDC hdc, LONG x, LONG y, LONG cx, LONG cy,
676                               OLE_XPOS_HIMETRIC xSrc,
677                               OLE_YPOS_HIMETRIC ySrc,
678                               OLE_XSIZE_HIMETRIC cxSrc,
679                               OLE_YSIZE_HIMETRIC cySrc,
680                               const RECT *bounds)
681 {
682     VARIANT ret, args[10];
683     HRESULT hr, hr_disp;
684     DISPPARAMS params;
685     IDispatch *disp;
686     int i;
687 
688     hr = IPicture_Render(iface, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, bounds);
689 
690     IPicture_QueryInterface(iface, &IID_IDispatch, (void**)&disp);
691 
692     /* This is broken on 64 bits - accepted pointer argument type is still VT_I4 */
693     for (i = 0; i < sizeof(args)/sizeof(args[0]); i++)
694         V_VT(&args[i]) = VT_I4;
695 
696     /* pack arguments and call */
697     V_INT_PTR(&args[0]) = (INT_PTR)bounds;
698     V_I4(&args[1]) = cySrc;
699     V_I4(&args[2]) = cxSrc;
700     V_I4(&args[3]) = ySrc;
701     V_I4(&args[4]) = xSrc;
702     V_I4(&args[5]) = cy;
703     V_I4(&args[6]) = cx;
704     V_I4(&args[7]) = y;
705     V_I4(&args[8]) = x;
706     V_I4(&args[9]) = HandleToLong(hdc);
707 
708     params.rgvarg = args;
709     params.rgdispidNamedArgs = NULL;
710     params.cArgs = 10;
711     params.cNamedArgs = 0;
712 
713     V_VT(&ret) = VT_EMPTY;
714     hr_disp = IDispatch_Invoke(disp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD,
715         &params, &ret, NULL, NULL);
716     ok(hr == hr_disp, "DISPID_PICT_RENDER returned wrong code, 0x%08x, expected 0x%08x\n",
717        hr_disp, hr);
718 
719     IDispatch_Release(disp);
720 
721     return hr;
722 }
723 
724 static void test_Render(void)
725 {
726     IPicture *pic;
727     HRESULT hres;
728     short type;
729     PICTDESC desc;
730     OLE_XSIZE_HIMETRIC pWidth;
731     OLE_YSIZE_HIMETRIC pHeight;
732     COLORREF result, expected;
733     HDC hdc = create_render_dc();
734 
735     /* test IPicture::Render return code on uninitialized picture */
736     hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
737     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
738     hres = IPicture_get_Type(pic, &type);
739     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
740     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
741     /* zero dimensions */
742     hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
743     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
744     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
745     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
746     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
747     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
748     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
749     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
750     hres = picture_render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
751     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
752     hres = picture_render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
753     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
754     hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
755     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
756     /* nonzero dimensions, PICTYPE_UNINITIALIZED */
757     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL);
758     ole_expect(hres, S_OK);
759     IPicture_Release(pic);
760 
761     desc.cbSizeofstruct = sizeof(PICTDESC);
762     desc.picType = PICTYPE_ICON;
763     desc.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
764     if(!desc.icon.hicon){
765         win_skip("LoadIcon failed. Skipping...\n");
766         delete_render_dc(hdc);
767         return;
768     }
769 
770     hres = OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (void **)&pic);
771     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
772     /* zero dimensions, PICTYPE_ICON */
773     hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
774     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
775     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
776     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
777     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
778     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
779     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
780     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
781     hres = picture_render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
782     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
783     hres = picture_render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
784     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
785     hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
786     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
787 
788     /* Check if target size and position is respected */
789     IPicture_get_Width(pic, &pWidth);
790     IPicture_get_Height(pic, &pHeight);
791 
792     SetPixelV(hdc, 0, 0, 0x00223344);
793     SetPixelV(hdc, 5, 5, 0x00223344);
794     SetPixelV(hdc, 10, 10, 0x00223344);
795     expected = GetPixel(hdc, 0, 0);
796 
797     hres = picture_render(pic, hdc, 1, 1, 9, 9, 0, 0, pWidth, -pHeight, NULL);
798     ole_expect(hres, S_OK);
799 
800     if(hres != S_OK) goto done;
801 
802     /* Evaluate the rendered Icon */
803     result = GetPixel(hdc, 0, 0);
804     ok(result == expected,
805        "Color at 0,0 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
806     result = GetPixel(hdc, 5, 5);
807     ok(result != expected,
808        "Color at 5,5 should have changed, but still was 0x%06X\n", expected);
809     result = GetPixel(hdc, 10, 10);
810     ok(result == expected,
811        "Color at 10,10 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
812 
813 done:
814     IPicture_Release(pic);
815     delete_render_dc(hdc);
816 }
817 
818 static void test_get_Attributes(void)
819 {
820     IPicture *pic;
821     HRESULT hres;
822     short type;
823     DWORD attr;
824 
825     hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
826     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
827     hres = IPicture_get_Type(pic, &type);
828     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
829     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
830 
831     hres = IPicture_get_Attributes(pic, NULL);
832     ole_expect(hres, E_POINTER);
833 
834     attr = 0xdeadbeef;
835     hres = IPicture_get_Attributes(pic, &attr);
836     ole_expect(hres, S_OK);
837     ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %d\n", attr);
838 
839     IPicture_Release(pic);
840 }
841 
842 static void test_get_Handle(void)
843 {
844     IPicture *pic;
845     HRESULT hres;
846 
847     hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
848     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
849     hres = IPicture_get_Handle(pic, NULL);
850     ole_expect(hres, E_POINTER);
851 
852     IPicture_Release(pic);
853 }
854 
855 static void test_get_Type(void)
856 {
857     IPicture *pic;
858     HRESULT hres;
859 
860     hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
861     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
862 
863     hres = IPicture_get_Type(pic, NULL);
864     ole_expect(hres, E_POINTER);
865 
866     IPicture_Release(pic);
867 }
868 
869 static void test_OleLoadPicturePath(void)
870 {
871     static WCHAR emptyW[] = {0};
872 
873     IPicture *pic;
874     HRESULT hres;
875     int i;
876     char temp_path[MAX_PATH];
877     char temp_file[MAX_PATH];
878     WCHAR temp_fileW[MAX_PATH + 5] = {'f','i','l','e',':','/','/','/'};
879     HANDLE file;
880     DWORD size;
881     WCHAR *ptr;
882     VARIANT var;
883 
884     const struct
885     {
886         LPOLESTR szURLorPath;
887         REFIID riid;
888         IPicture **pic;
889     } invalid_parameters[] =
890     {
891         {NULL,  NULL,          NULL},
892         {NULL,  NULL,          &pic},
893         {NULL,  &IID_IPicture, NULL},
894         {NULL,  &IID_IPicture, &pic},
895         {emptyW, NULL,          NULL},
896         {emptyW, &IID_IPicture, NULL},
897     };
898 
899     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
900     {
901         pic = (IPicture *)0xdeadbeef;
902         hres = OleLoadPicturePath(invalid_parameters[i].szURLorPath, NULL, 0, 0,
903                                   invalid_parameters[i].riid,
904                                   (void **)invalid_parameters[i].pic);
905         ok(hres == E_INVALIDARG,
906            "[%d] Expected OleLoadPicturePath to return E_INVALIDARG, got 0x%08x\n", i, hres);
907         ok(pic == (IPicture *)0xdeadbeef,
908            "[%d] Expected output pointer to be 0xdeadbeef, got %p\n", i, pic);
909     }
910 
911     pic = (IPicture *)0xdeadbeef;
912     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, NULL, (void **)&pic);
913     todo_wine
914     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
915        broken(hres == E_UNEXPECTED) || /* NT4 */
916        broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
917        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
918     ok(pic == NULL,
919        "Expected the output interface pointer to be NULL, got %p\n", pic);
920 
921     pic = (IPicture *)0xdeadbeef;
922     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
923     todo_wine
924     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
925        broken(hres == E_UNEXPECTED) || /* NT4 */
926        broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
927        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
928     ok(pic == NULL,
929        "Expected the output interface pointer to be NULL, got %p\n", pic);
930 
931     /* Create a local temporary image file for testing. */
932     GetTempPathA(sizeof(temp_path), temp_path);
933     GetTempFileNameA(temp_path, "bmp", 0, temp_file);
934     file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
935                        FILE_ATTRIBUTE_NORMAL, NULL);
936     WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
937     CloseHandle(file);
938 
939     MultiByteToWideChar(CP_ACP, 0, temp_file, -1, temp_fileW + 8, sizeof(temp_fileW)/sizeof(WCHAR) - 8);
940 
941     /* Try a normal DOS path. */
942     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
943     ok(hres == S_OK ||
944        broken(hres == E_UNEXPECTED), /* NT4 */
945        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
946     if (pic)
947         IPicture_Release(pic);
948 
949     VariantInit(&var);
950     V_VT(&var) = VT_BSTR;
951     V_BSTR(&var) = SysAllocString(temp_fileW + 8);
952     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
953     ok(hres == S_OK, "OleLoadPictureFile error %#x\n", hres);
954     IPicture_Release(pic);
955     VariantClear(&var);
956 
957     /* Try a DOS path with tacked on "file:". */
958     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
959     ok(hres == S_OK ||
960        broken(hres == E_UNEXPECTED), /* NT4 */
961        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
962     if (pic)
963         IPicture_Release(pic);
964 
965     VariantInit(&var);
966     V_VT(&var) = VT_BSTR;
967     V_BSTR(&var) = SysAllocString(temp_fileW);
968     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
969     ok(hres == CTL_E_PATHFILEACCESSERROR, "wrong error %#x\n", hres);
970     VariantClear(&var);
971 
972     DeleteFileA(temp_file);
973 
974     /* Try with a nonexistent file. */
975     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
976     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
977        broken(hres == E_UNEXPECTED) || /* NT4 */
978        broken(hres == E_FAIL), /*Win2k */
979        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
980 
981     VariantInit(&var);
982     V_VT(&var) = VT_BSTR;
983     V_BSTR(&var) = SysAllocString(temp_fileW + 8);
984     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
985     ok(hres == CTL_E_FILENOTFOUND, "wrong error %#x\n", hres);
986     VariantClear(&var);
987 
988     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
989     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
990        broken(hres == E_UNEXPECTED) || /* NT4 */
991        broken(hres == E_FAIL), /* Win2k */
992        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
993 
994     VariantInit(&var);
995     V_VT(&var) = VT_BSTR;
996     V_BSTR(&var) = SysAllocString(temp_fileW);
997     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
998     ok(hres == CTL_E_PATHFILEACCESSERROR, "wrong error %#x\n", hres);
999     VariantClear(&var);
1000 
1001     file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1002                        FILE_ATTRIBUTE_NORMAL, NULL);
1003     WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
1004     CloseHandle(file);
1005 
1006     /* Try a "file:" URL with slash separators. */
1007     ptr = temp_fileW + 8;
1008     while (*ptr)
1009     {
1010         if (*ptr == '\\')
1011             *ptr = '/';
1012         ptr++;
1013     }
1014 
1015     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
1016     ok(hres == S_OK ||
1017        broken(hres == E_UNEXPECTED), /* NT4 */
1018        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
1019     if (pic)
1020         IPicture_Release(pic);
1021 
1022     VariantInit(&var);
1023     V_VT(&var) = VT_BSTR;
1024     V_BSTR(&var) = SysAllocString(temp_fileW);
1025     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1026     ok(hres == CTL_E_PATHFILEACCESSERROR, "wrong error %#x\n", hres);
1027     VariantClear(&var);
1028 
1029     DeleteFileA(temp_file);
1030 
1031     /* Try with a nonexistent file. */
1032     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
1033     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
1034        broken(hres == E_UNEXPECTED) || /* NT4 */
1035        broken(hres == E_FAIL), /* Win2k */
1036        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
1037 
1038     VariantInit(&var);
1039     V_VT(&var) = VT_BSTR;
1040     V_BSTR(&var) = SysAllocString(temp_fileW);
1041     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1042     ok(hres == CTL_E_PATHFILEACCESSERROR, "wrong error %#x\n", hres);
1043     VariantClear(&var);
1044 
1045     VariantInit(&var);
1046     V_VT(&var) = VT_INT;
1047     V_INT(&var) = 762;
1048     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1049     ok(hres == CTL_E_FILENOTFOUND, "wrong error %#x\n", hres);
1050 
1051 if (0) /* crashes under Windows */
1052     hres = OleLoadPictureFile(var, NULL);
1053 }
1054 
1055 static void test_himetric(void)
1056 {
1057     static const BYTE bmp_bits[1024];
1058     OLE_XSIZE_HIMETRIC cx;
1059     OLE_YSIZE_HIMETRIC cy;
1060     IPicture *pic;
1061     PICTDESC desc;
1062     HBITMAP bmp;
1063     HRESULT hr;
1064     HICON icon;
1065     HDC hdc;
1066     INT d;
1067 
1068     desc.cbSizeofstruct = sizeof(desc);
1069     desc.picType = PICTYPE_BITMAP;
1070     desc.bmp.hpal = NULL;
1071 
1072     hdc = CreateCompatibleDC(0);
1073 
1074     bmp = CreateBitmap(1.9 * GetDeviceCaps(hdc, LOGPIXELSX),
1075                        1.9 * GetDeviceCaps(hdc, LOGPIXELSY), 1, 1, NULL);
1076 
1077     desc.bmp.hbitmap = bmp;
1078 
1079     /* size in himetric units reported rounded up to next integer value */
1080     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1081     ok(hr == S_OK, "got 0x%08x\n", hr);
1082 
1083     cx = 0;
1084     d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSX)), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
1085     hr = IPicture_get_Width(pic, &cx);
1086     ok(hr == S_OK, "got 0x%08x\n", hr);
1087     ok(cx == d, "got %d, expected %d\n", cx, d);
1088 
1089     cy = 0;
1090     d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSY)), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
1091     hr = IPicture_get_Height(pic, &cy);
1092     ok(hr == S_OK, "got 0x%08x\n", hr);
1093     ok(cy == d, "got %d, expected %d\n", cy, d);
1094 
1095     DeleteObject(bmp);
1096     IPicture_Release(pic);
1097 
1098     /* same thing with icon */
1099     icon = CreateIcon(NULL, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
1100                       1, 1, bmp_bits, bmp_bits);
1101     ok(icon != NULL, "failed to create icon\n");
1102 
1103     desc.picType = PICTYPE_ICON;
1104     desc.icon.hicon = icon;
1105 
1106     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1107     ok(hr == S_OK, "got 0x%08x\n", hr);
1108 
1109     cx = 0;
1110     d = MulDiv(GetSystemMetrics(SM_CXICON), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
1111     hr = IPicture_get_Width(pic, &cx);
1112     ok(hr == S_OK, "got 0x%08x\n", hr);
1113     ok(cx == d, "got %d, expected %d\n", cx, d);
1114 
1115     cy = 0;
1116     d = MulDiv(GetSystemMetrics(SM_CYICON), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
1117     hr = IPicture_get_Height(pic, &cy);
1118     ok(hr == S_OK, "got 0x%08x\n", hr);
1119     ok(cy == d, "got %d, expected %d\n", cy, d);
1120 
1121     IPicture_Release(pic);
1122     DestroyIcon(icon);
1123 
1124     DeleteDC(hdc);
1125 }
1126 
1127 static void test_load_save_bmp(void)
1128 {
1129     IPicture *pic;
1130     PICTDESC desc;
1131     short type;
1132     OLE_HANDLE handle;
1133     HGLOBAL hmem;
1134     DWORD *mem;
1135     IPersistStream *src_stream;
1136     IStream *dst_stream;
1137     LARGE_INTEGER offset;
1138     HRESULT hr;
1139     LONG size;
1140 
1141     desc.cbSizeofstruct = sizeof(desc);
1142     desc.picType = PICTYPE_BITMAP;
1143     desc.bmp.hpal = 0;
1144     desc.bmp.hbitmap = CreateBitmap(1, 1, 1, 1, NULL);
1145     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1146     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
1147 
1148     type = -1;
1149     hr = IPicture_get_Type(pic, &type);
1150     ok(hr == S_OK,"get_Type error %#8x\n", hr);
1151     ok(type == PICTYPE_BITMAP,"expected picture type PICTYPE_BITMAP, got %d\n", type);
1152 
1153     hr = IPicture_get_Handle(pic, &handle);
1154     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1155     ok(IntToPtr(handle) == desc.bmp.hbitmap, "get_Handle returned wrong handle %#x\n", handle);
1156 
1157     hmem = GlobalAlloc(GMEM_ZEROINIT, 4096);
1158     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
1159     ok(hr == S_OK, "createstreamonhglobal error %#x\n", hr);
1160 
1161     size = -1;
1162     hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
1163     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1164     ok(size == 66, "expected 66, got %d\n", size);
1165     mem = GlobalLock(hmem);
1166     ok(!memcmp(&mem[0], "BM", 2), "got wrong bmp header %04x\n", mem[0]);
1167     GlobalUnlock(hmem);
1168 
1169     size = -1;
1170     hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
1171     ok(hr == E_FAIL, "expected E_FAIL, got %#x\n", hr);
1172     ok(size == -1, "expected -1, got %d\n", size);
1173 
1174     offset.QuadPart = 0;
1175     hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
1176     ok(hr == S_OK, "IStream_Seek %#x\n", hr);
1177 
1178     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
1179     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1180 
1181     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
1182     ok(hr == S_OK, "Save error %#x\n", hr);
1183 
1184     IPersistStream_Release(src_stream);
1185     IStream_Release(dst_stream);
1186 
1187     mem = GlobalLock(hmem);
1188     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
1189     ok(mem[1] == 66, "expected stream size 66, got %u\n", mem[1]);
1190     ok(!memcmp(&mem[2], "BM", 2), "got wrong bmp header %04x\n", mem[2]);
1191 
1192     GlobalUnlock(hmem);
1193     GlobalFree(hmem);
1194 
1195     DeleteObject(desc.bmp.hbitmap);
1196     IPicture_Release(pic);
1197 }
1198 
1199 static void test_load_save_icon(void)
1200 {
1201     IPicture *pic;
1202     PICTDESC desc;
1203     short type;
1204     OLE_HANDLE handle;
1205     HGLOBAL hmem;
1206     DWORD *mem;
1207     IPersistStream *src_stream;
1208     IStream *dst_stream;
1209     LARGE_INTEGER offset;
1210     HRESULT hr;
1211     LONG size;
1212 
1213     desc.cbSizeofstruct = sizeof(desc);
1214     desc.picType = PICTYPE_ICON;
1215     desc.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
1216     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1217     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
1218 
1219     type = -1;
1220     hr = IPicture_get_Type(pic, &type);
1221     ok(hr == S_OK,"get_Type error %#8x\n", hr);
1222     ok(type == PICTYPE_ICON,"expected picture type PICTYPE_ICON, got %d\n", type);
1223 
1224     hr = IPicture_get_Handle(pic, &handle);
1225     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1226     ok(IntToPtr(handle) == desc.icon.hicon, "get_Handle returned wrong handle %#x\n", handle);
1227 
1228     hmem = GlobalAlloc(GMEM_ZEROINIT, 8192);
1229     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
1230     ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
1231 
1232     size = -1;
1233     hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
1234     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1235 todo_wine
1236     ok(size == 766, "expected 766, got %d\n", size);
1237     mem = GlobalLock(hmem);
1238     ok(mem[0] == 0x00010000, "got wrong icon header %04x\n", mem[0]);
1239     GlobalUnlock(hmem);
1240 
1241     size = -1;
1242     hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
1243     ok(hr == E_FAIL, "expected E_FAIL, got %#x\n", hr);
1244     ok(size == -1, "expected -1, got %d\n", size);
1245 
1246     offset.QuadPart = 0;
1247     hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
1248     ok(hr == S_OK, "IStream_Seek %#x\n", hr);
1249 
1250     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
1251     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1252 
1253     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
1254     ok(hr == S_OK, "Saveerror %#x\n", hr);
1255 
1256     IPersistStream_Release(src_stream);
1257     IStream_Release(dst_stream);
1258 
1259     mem = GlobalLock(hmem);
1260     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
1261 todo_wine
1262     ok(mem[1] == 766, "expected stream size 766, got %u\n", mem[1]);
1263     ok(mem[2] == 0x00010000, "got wrong icon header %04x\n", mem[2]);
1264 
1265     GlobalUnlock(hmem);
1266     GlobalFree(hmem);
1267 
1268     DestroyIcon(desc.icon.hicon);
1269     IPicture_Release(pic);
1270 }
1271 
1272 static void test_load_save_empty_picture(void)
1273 {
1274     IPicture *pic;
1275     PICTDESC desc;
1276     short type;
1277     OLE_HANDLE handle;
1278     HGLOBAL hmem;
1279     DWORD *mem;
1280     IPersistStream *src_stream;
1281     IStream *dst_stream, *stream;
1282     LARGE_INTEGER offset;
1283     HRESULT hr;
1284     LONG size;
1285 
1286     memset(&pic, 0, sizeof(pic));
1287     desc.cbSizeofstruct = sizeof(desc);
1288     desc.picType = PICTYPE_NONE;
1289     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void **)&pic);
1290     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
1291 
1292     type = -1;
1293     hr = IPicture_get_Type(pic, &type);
1294     ok(hr == S_OK, "get_Type error %#x\n", hr);
1295     ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
1296 
1297     handle = (OLE_HANDLE)0xdeadbeef;
1298     hr = IPicture_get_Handle(pic, &handle);
1299     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1300     ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
1301 
1302     hmem = GlobalAlloc(GMEM_ZEROINIT, 4096);
1303     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
1304     ok(hr == S_OK, "createstreamonhglobal error %#x\n", hr);
1305 
1306     size = -1;
1307     hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
1308     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1309     ok(size == -1, "expected -1, got %d\n", size);
1310 
1311     size = -1;
1312     hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
1313     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1314     ok(size == -1, "expected -1, got %d\n", size);
1315 
1316     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
1317     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1318 
1319     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
1320     ok(hr == S_OK, "Save error %#x\n", hr);
1321 
1322     mem = GlobalLock(hmem);
1323     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
1324     ok(mem[1] == 0, "expected stream size 0, got %u\n", mem[1]);
1325     GlobalUnlock(hmem);
1326 
1327     IPersistStream_Release(src_stream);
1328     IPicture_Release(pic);
1329 
1330     /* first with statable and seekable stream */
1331     offset.QuadPart = 0;
1332     hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
1333     ok(hr == S_OK, "IStream_Seek %#x\n", hr);
1334 
1335     pic = NULL;
1336     hr = pOleLoadPicture(dst_stream, 0, FALSE, &IID_IPicture, (void **)&pic);
1337     ok(hr == S_OK, "OleLoadPicture error %#x\n", hr);
1338     ok(pic != NULL,"picture should not be not NULL\n");
1339     if (pic != NULL)
1340     {
1341         type = -1;
1342         hr = IPicture_get_Type(pic, &type);
1343         ok(hr == S_OK,"get_Type error %#8x\n", hr);
1344         ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
1345 
1346         handle = (OLE_HANDLE)0xdeadbeef;
1347         hr = IPicture_get_Handle(pic, &handle);
1348         ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1349         ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
1350 
1351         IPicture_Release(pic);
1352     }
1353     IStream_Release(dst_stream);
1354 
1355     /* again with non-statable and non-seekable stream */
1356     stream = NoStatStream_Construct(hmem);
1357     ok(stream != NULL, "failed to create empty image stream\n");
1358 
1359     pic = NULL;
1360     hr = pOleLoadPicture(stream, 0, FALSE, &IID_IPicture, (void **)&pic);
1361     ok(hr == S_OK, "OleLoadPicture error %#x\n", hr);
1362     ok(pic != NULL,"picture should not be not NULL\n");
1363     if (pic != NULL)
1364     {
1365         type = -1;
1366         hr = IPicture_get_Type(pic, &type);
1367         ok(hr == S_OK,"get_Type error %#8x\n", hr);
1368         ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
1369 
1370         handle = (OLE_HANDLE)0xdeadbeef;
1371         hr = IPicture_get_Handle(pic, &handle);
1372         ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1373         ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
1374 
1375         IPicture_Release(pic);
1376     }
1377     /* Non-statable impl always deletes on release */
1378     IStream_Release(stream);
1379 }
1380 
1381 static void test_load_save_emf(void)
1382 {
1383     HDC hdc;
1384     IPicture *pic;
1385     PICTDESC desc;
1386     short type;
1387     OLE_HANDLE handle;
1388     HGLOBAL hmem;
1389     DWORD *mem;
1390     ENHMETAHEADER *emh;
1391     IPersistStream *src_stream;
1392     IStream *dst_stream;
1393     LARGE_INTEGER offset;
1394     HRESULT hr;
1395     LONG size;
1396 
1397     hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
1398     ok(hdc != 0, "CreateEnhMetaFileA failed\n");
1399 
1400     desc.cbSizeofstruct = sizeof(desc);
1401     desc.picType = PICTYPE_ENHMETAFILE;
1402     desc.emf.hemf = CloseEnhMetaFile(hdc);
1403     ok(desc.emf.hemf != 0, "CloseEnhMetaFile failed\n");
1404     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1405     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
1406 
1407     type = -1;
1408     hr = IPicture_get_Type(pic, &type);
1409     ok(hr == S_OK,"get_Type error %#8x\n", hr);
1410     ok(type == PICTYPE_ENHMETAFILE,"expected PICTYPE_ENHMETAFILE, got %d\n", type);
1411 
1412     hr = IPicture_get_Handle(pic, &handle);
1413     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1414     ok(IntToPtr(handle) == desc.emf.hemf, "get_Handle returned wrong handle %#x\n", handle);
1415 
1416     hmem = GlobalAlloc(GMEM_MOVEABLE, 0);
1417     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
1418     ok(hr == S_OK, "createstreamonhglobal error %#x\n", hr);
1419 
1420     size = -1;
1421     hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
1422     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1423     ok(size == 128, "expected 128, got %d\n", size);
1424     emh = GlobalLock(hmem);
1425 if (size)
1426 {
1427     ok(emh->iType == EMR_HEADER, "wrong iType %04x\n", emh->iType);
1428     ok(emh->dSignature == ENHMETA_SIGNATURE, "wrong dSignature %08x\n", emh->dSignature);
1429 }
1430     GlobalUnlock(hmem);
1431 
1432     size = -1;
1433     hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
1434     ok(hr == E_FAIL, "expected E_FAIL, got %#x\n", hr);
1435     ok(size == -1, "expected -1, got %d\n", size);
1436 
1437     offset.QuadPart = 0;
1438     hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
1439     ok(hr == S_OK, "IStream_Seek %#x\n", hr);
1440 
1441     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
1442     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1443 
1444     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
1445     ok(hr == S_OK, "Save error %#x\n", hr);
1446 
1447     IPersistStream_Release(src_stream);
1448     IStream_Release(dst_stream);
1449 
1450     mem = GlobalLock(hmem);
1451     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
1452     ok(mem[1] == 128, "expected 128, got %u\n", mem[1]);
1453     emh = (ENHMETAHEADER *)(mem + 2);
1454     ok(emh->iType == EMR_HEADER, "wrong iType %04x\n", emh->iType);
1455     ok(emh->dSignature == ENHMETA_SIGNATURE, "wrong dSignature %08x\n", emh->dSignature);
1456 
1457     GlobalUnlock(hmem);
1458     GlobalFree(hmem);
1459 
1460     DeleteEnhMetaFile(desc.emf.hemf);
1461     IPicture_Release(pic);
1462 }
1463 
1464 START_TEST(olepicture)
1465 {
1466     hOleaut32 = GetModuleHandleA("oleaut32.dll");
1467     pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
1468     pOleLoadPictureEx = (void*)GetProcAddress(hOleaut32, "OleLoadPictureEx");
1469     if (!pOleLoadPicture)
1470     {
1471         win_skip("OleLoadPicture is not available\n");
1472         return;
1473     }
1474 
1475     /* Test regular 1x1 pixel images of gif, jpg, bmp type */
1476     test_pic(gifimage, sizeof(gifimage));
1477     test_pic(jpgimage, sizeof(jpgimage));
1478     test_pic(bmpimage, sizeof(bmpimage));
1479     test_pic(bmpimage_rle8, sizeof(bmpimage_rle8));
1480     test_pic(gif4pixel, sizeof(gif4pixel));
1481     /* FIXME: No PNG support in Windows... */
1482     if (0) test_pic(pngimage, sizeof(pngimage));
1483     test_empty_image();
1484     test_empty_image_2();
1485     if (pOleLoadPictureEx)
1486     {
1487         test_apm();
1488         test_metafile();
1489         test_enhmetafile();
1490     }
1491     else
1492         win_skip("OleLoadPictureEx is not available\n");
1493     test_Invoke();
1494     test_OleCreatePictureIndirect();
1495     test_Render();
1496     test_get_Attributes();
1497     test_get_Handle();
1498     test_get_Type();
1499     test_OleLoadPicturePath();
1500     test_himetric();
1501     test_load_save_bmp();
1502     test_load_save_icon();
1503     test_load_save_empty_picture();
1504     test_load_save_emf();
1505 }
1506 
1507 
1508 /* Helper functions only ... */
1509 
1510 
1511 static inline NoStatStreamImpl *impl_from_IStream(IStream *iface)
1512 {
1513   return CONTAINING_RECORD(iface, NoStatStreamImpl, IStream_iface);
1514 }
1515 
1516 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
1517 {
1518   GlobalFree(This->supportHandle);
1519   This->supportHandle=0;
1520   HeapFree(GetProcessHeap(), 0, This);
1521 }
1522 
1523 static ULONG WINAPI NoStatStreamImpl_AddRef(
1524 		IStream* iface)
1525 {
1526   NoStatStreamImpl* const This = impl_from_IStream(iface);
1527   return InterlockedIncrement(&This->ref);
1528 }
1529 
1530 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
1531 		  IStream*     iface,
1532 		  REFIID         riid,	      /* [in] */
1533 		  void**         ppvObject)   /* [iid_is][out] */
1534 {
1535   NoStatStreamImpl* const This = impl_from_IStream(iface);
1536   if (ppvObject==0) return E_INVALIDARG;
1537   *ppvObject = 0;
1538 
1539   if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IStream, riid))
1540     *ppvObject = &This->IStream_iface;
1541 
1542   if ((*ppvObject)==0)
1543     return E_NOINTERFACE;
1544   NoStatStreamImpl_AddRef(iface);
1545   return S_OK;
1546 }
1547 
1548 static ULONG WINAPI NoStatStreamImpl_Release(
1549 		IStream* iface)
1550 {
1551   NoStatStreamImpl* const This = impl_from_IStream(iface);
1552   ULONG newRef = InterlockedDecrement(&This->ref);
1553   if (newRef==0)
1554     NoStatStreamImpl_Destroy(This);
1555   return newRef;
1556 }
1557 
1558 static HRESULT WINAPI NoStatStreamImpl_Read(
1559 		  IStream*     iface,
1560 		  void*          pv,        /* [length_is][size_is][out] */
1561 		  ULONG          cb,        /* [in] */
1562 		  ULONG*         pcbRead)   /* [out] */
1563 {
1564   NoStatStreamImpl* const This = impl_from_IStream(iface);
1565   void* supportBuffer;
1566   ULONG bytesReadBuffer;
1567   ULONG bytesToReadFromBuffer;
1568 
1569   if (pcbRead==0)
1570     pcbRead = &bytesReadBuffer;
1571   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
1572   supportBuffer = GlobalLock(This->supportHandle);
1573   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
1574   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
1575   *pcbRead = bytesToReadFromBuffer;
1576   GlobalUnlock(This->supportHandle);
1577   if(*pcbRead == cb)
1578     return S_OK;
1579   return S_FALSE;
1580 }
1581 
1582 static HRESULT WINAPI NoStatStreamImpl_Write(
1583 	          IStream*     iface,
1584 		  const void*    pv,          /* [size_is][in] */
1585 		  ULONG          cb,          /* [in] */
1586 		  ULONG*         pcbWritten)  /* [out] */
1587 {
1588   NoStatStreamImpl* const This = impl_from_IStream(iface);
1589   void*          supportBuffer;
1590   ULARGE_INTEGER newSize;
1591   ULONG          bytesWritten = 0;
1592 
1593   if (pcbWritten == 0)
1594     pcbWritten = &bytesWritten;
1595   if (cb == 0)
1596     return S_OK;
1597   newSize.u.HighPart = 0;
1598   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
1599   if (newSize.u.LowPart > This->streamSize.u.LowPart)
1600    IStream_SetSize(iface, newSize);
1601 
1602   supportBuffer = GlobalLock(This->supportHandle);
1603   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
1604   This->currentPosition.u.LowPart+=cb;
1605   *pcbWritten = cb;
1606   GlobalUnlock(This->supportHandle);
1607   return S_OK;
1608 }
1609 
1610 static HRESULT WINAPI NoStatStreamImpl_Seek(
1611 		  IStream*      iface,
1612 		  LARGE_INTEGER   dlibMove,         /* [in] */
1613 		  DWORD           dwOrigin,         /* [in] */
1614 		  ULARGE_INTEGER* plibNewPosition) /* [out] */
1615 {
1616   NoStatStreamImpl* const This = impl_from_IStream(iface);
1617   ULARGE_INTEGER newPosition;
1618   switch (dwOrigin)
1619   {
1620     case STREAM_SEEK_SET:
1621       newPosition.u.HighPart = 0;
1622       newPosition.u.LowPart = 0;
1623       break;
1624     case STREAM_SEEK_CUR:
1625       newPosition = This->currentPosition;
1626       break;
1627     case STREAM_SEEK_END:
1628       newPosition = This->streamSize;
1629       break;
1630     default:
1631       return STG_E_INVALIDFUNCTION;
1632   }
1633   if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
1634       return STG_E_INVALIDFUNCTION;
1635   newPosition.QuadPart += dlibMove.QuadPart;
1636   if (plibNewPosition) *plibNewPosition = newPosition;
1637   This->currentPosition = newPosition;
1638   return S_OK;
1639 }
1640 
1641 static HRESULT WINAPI NoStatStreamImpl_SetSize(
1642 				     IStream*      iface,
1643 				     ULARGE_INTEGER  libNewSize)   /* [in] */
1644 {
1645   NoStatStreamImpl* const This = impl_from_IStream(iface);
1646   HGLOBAL supportHandle;
1647   if (libNewSize.u.HighPart != 0)
1648     return STG_E_INVALIDFUNCTION;
1649   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
1650     return S_OK;
1651   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
1652   if (supportHandle == 0)
1653     return STG_E_MEDIUMFULL;
1654   This->supportHandle = supportHandle;
1655   This->streamSize.u.LowPart = libNewSize.u.LowPart;
1656   return S_OK;
1657 }
1658 
1659 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
1660 				    IStream*      iface,
1661 				    IStream*      pstm,         /* [unique][in] */
1662 				    ULARGE_INTEGER  cb,           /* [in] */
1663 				    ULARGE_INTEGER* pcbRead,      /* [out] */
1664 				    ULARGE_INTEGER* pcbWritten)   /* [out] */
1665 {
1666   HRESULT        hr = S_OK;
1667   BYTE           tmpBuffer[128];
1668   ULONG          bytesRead, bytesWritten, copySize;
1669   ULARGE_INTEGER totalBytesRead;
1670   ULARGE_INTEGER totalBytesWritten;
1671 
1672   if ( pstm == 0 )
1673     return STG_E_INVALIDPOINTER;
1674   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
1675   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
1676 
1677   while ( cb.u.LowPart > 0 )
1678   {
1679     if ( cb.u.LowPart >= 128 )
1680       copySize = 128;
1681     else
1682       copySize = cb.u.LowPart;
1683     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1684     totalBytesRead.u.LowPart += bytesRead;
1685     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1686     totalBytesWritten.u.LowPart += bytesWritten;
1687     if (bytesRead != bytesWritten)
1688     {
1689       hr = STG_E_MEDIUMFULL;
1690       break;
1691     }
1692     if (bytesRead!=copySize)
1693       cb.u.LowPart = 0;
1694     else
1695       cb.u.LowPart -= bytesRead;
1696   }
1697   if (pcbRead)
1698   {
1699     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
1700     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
1701   }
1702 
1703   if (pcbWritten)
1704   {
1705     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
1706     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
1707   }
1708   return hr;
1709 }
1710 
1711 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
1712 {
1713   return S_OK;
1714 }
1715 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
1716 
1717 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
1718 		  IStream*       iface,
1719 		  ULARGE_INTEGER libOffset,   /* [in] */
1720 		  ULARGE_INTEGER cb,          /* [in] */
1721 		  DWORD          dwLockType)  /* [in] */
1722 {
1723   return S_OK;
1724 }
1725 
1726 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
1727 		  IStream*       iface,
1728 		  ULARGE_INTEGER libOffset,   /* [in] */
1729 		  ULARGE_INTEGER cb,          /* [in] */
1730 		  DWORD          dwLockType)  /* [in] */
1731 {
1732   return S_OK;
1733 }
1734 
1735 static HRESULT WINAPI NoStatStreamImpl_Stat(
1736 		  IStream*     iface,
1737 		  STATSTG*     pstatstg,     /* [out] */
1738 		  DWORD        grfStatFlag)  /* [in] */
1739 {
1740   return E_NOTIMPL;
1741 }
1742 
1743 static HRESULT WINAPI NoStatStreamImpl_Clone(
1744 		  IStream*     iface,
1745 		  IStream**    ppstm) /* [out] */
1746 {
1747   return E_NOTIMPL;
1748 }
1749 static const IStreamVtbl NoStatStreamImpl_Vtbl;
1750 
1751 /*
1752     Build an object that implements IStream, without IStream_Stat capabilities.
1753     Receives a memory handle with data buffer. If memory handle is non-null,
1754     it is assumed to be unlocked, otherwise an internal memory handle is allocated.
1755     In any case the object takes ownership of memory handle and will free it on
1756     object release.
1757  */
1758 static IStream* NoStatStream_Construct(HGLOBAL hGlobal)
1759 {
1760   NoStatStreamImpl* newStream;
1761 
1762   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
1763   if (newStream!=0)
1764   {
1765     newStream->IStream_iface.lpVtbl = &NoStatStreamImpl_Vtbl;
1766     newStream->ref    = 1;
1767     newStream->supportHandle = hGlobal;
1768 
1769     if (!newStream->supportHandle)
1770       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
1771 					     GMEM_SHARE, 0);
1772     newStream->currentPosition.u.HighPart = 0;
1773     newStream->currentPosition.u.LowPart = 0;
1774     newStream->streamSize.u.HighPart = 0;
1775     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
1776   }
1777   return &newStream->IStream_iface;
1778 }
1779 
1780 
1781 static const IStreamVtbl NoStatStreamImpl_Vtbl =
1782 {
1783     NoStatStreamImpl_QueryInterface,
1784     NoStatStreamImpl_AddRef,
1785     NoStatStreamImpl_Release,
1786     NoStatStreamImpl_Read,
1787     NoStatStreamImpl_Write,
1788     NoStatStreamImpl_Seek,
1789     NoStatStreamImpl_SetSize,
1790     NoStatStreamImpl_CopyTo,
1791     NoStatStreamImpl_Commit,
1792     NoStatStreamImpl_Revert,
1793     NoStatStreamImpl_LockRegion,
1794     NoStatStreamImpl_UnlockRegion,
1795     NoStatStreamImpl_Stat,
1796     NoStatStreamImpl_Clone
1797 };
1798