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 < ARRAY_SIZE(args); 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 HRESULT create_picture(short type, IPicture **pict)
554 {
555     PICTDESC desc;
556 
557     desc.cbSizeofstruct = sizeof(desc);
558     desc.picType = type;
559 
560     switch (type)
561     {
562     case PICTYPE_UNINITIALIZED:
563         return OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)pict);
564 
565     case PICTYPE_NONE:
566         break;
567 
568     case PICTYPE_BITMAP:
569         desc.bmp.hbitmap = CreateBitmap(1, 1, 1, 1, NULL);
570         desc.bmp.hpal = (HPALETTE)0xbeefdead;
571         break;
572 
573     case PICTYPE_ICON:
574         desc.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
575         break;
576 
577     case PICTYPE_METAFILE:
578     {
579         HDC hdc = CreateMetaFileA(NULL);
580         desc.wmf.hmeta = CloseMetaFile(hdc);
581         desc.wmf.xExt = 1;
582         desc.wmf.yExt = 1;
583         break;
584     }
585 
586     case PICTYPE_ENHMETAFILE:
587     {
588         HDC hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
589         desc.emf.hemf = CloseEnhMetaFile(hdc);
590         break;
591     }
592 
593     default:
594         ok(0, "picture type %d is not supported\n", type);
595         return E_NOTIMPL;
596     }
597 
598     return OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (void **)pict);
599 }
600 
601 static void test_OleCreatePictureIndirect(void)
602 {
603     PICTDESC desc;
604     OLE_HANDLE handle;
605     IPicture *pict;
606     HRESULT hr;
607     short type, i;
608 
609 if (0)
610 {
611     /* crashes on native */
612     OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, NULL);
613 }
614 
615     desc.cbSizeofstruct = sizeof(desc);
616     desc.picType = PICTYPE_UNINITIALIZED;
617     pict = (void *)0xdeadbeef;
618     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (void **)&pict);
619     ok(hr == E_UNEXPECTED, "got %#x\n", hr);
620     ok(pict == NULL, "got %p\n", pict);
621 
622     for (i = PICTYPE_UNINITIALIZED; i <= PICTYPE_ENHMETAFILE; i++)
623     {
624         hr = create_picture(i, &pict);
625         ok(hr == S_OK, "%d: got %#x\n", i, hr);
626 
627         type = 0xdead;
628         hr = IPicture_get_Type(pict, &type);
629         ok(hr == S_OK, "%d: got %#x\n", i, hr);
630         ok(type == i, "%d: got %d\n", i, type);
631 
632         handle = 0xdeadbeef;
633         hr = IPicture_get_Handle(pict, &handle);
634         ok(hr == S_OK, "%d: got %#x\n", i, hr);
635         if (type == PICTYPE_UNINITIALIZED || type == PICTYPE_NONE)
636             ok(handle == 0, "%d: got %#x\n", i, handle);
637         else
638             ok(handle != 0 && handle != 0xdeadbeef, "%d: got %#x\n", i, handle);
639 
640         handle = 0xdeadbeef;
641         hr = IPicture_get_hPal(pict, &handle);
642         if (type == PICTYPE_BITMAP)
643         {
644             ok(hr == S_OK, "%d: got %#x\n", i, hr);
645             ok(handle == 0xbeefdead, "%d: got %#x\n", i, handle);
646         }
647         else
648         {
649             ok(hr == E_FAIL, "%d: got %#x\n", i, hr);
650             ok(handle == 0xdeadbeef || handle == 0 /* win64 */, "%d: got %#x\n", i, handle);
651         }
652 
653         hr = IPicture_set_hPal(pict, HandleToUlong(GetStockObject(DEFAULT_PALETTE)));
654         if (type == PICTYPE_BITMAP)
655             ok(hr == S_OK, "%d: got %#x\n", i, hr);
656         else
657             ok(hr == E_FAIL, "%d: got %#x\n", i, hr);
658 
659         IPicture_Release(pict);
660     }
661 }
662 
663 static void test_apm(void)
664 {
665     OLE_HANDLE handle;
666     LPSTREAM stream;
667     IPicture *pict;
668     HGLOBAL hglob;
669     LPBYTE *data;
670     LONG cxy;
671     BOOL keep;
672     short type;
673 
674     hglob = GlobalAlloc (0, sizeof(apmdata));
675     data = GlobalLock(hglob);
676     memcpy(data, apmdata, sizeof(apmdata));
677 
678     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
679     ole_check(pOleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
680 
681     ole_check(IPicture_get_Handle(pict, &handle));
682     ok(handle != 0, "handle is null\n");
683 
684     ole_check(IPicture_get_Type(pict, &type));
685     expect_eq(type, PICTYPE_METAFILE, short, "%d");
686 
687     ole_check(IPicture_get_Height(pict, &cxy));
688     expect_eq(cxy,  1667, LONG, "%d");
689 
690     ole_check(IPicture_get_Width(pict, &cxy));
691     expect_eq(cxy,  1323, LONG, "%d");
692 
693     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
694     todo_wine expect_eq(keep, FALSE, LONG, "%d");
695 
696     ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
697     IPicture_Release(pict);
698     IStream_Release(stream);
699 }
700 
701 static void test_metafile(void)
702 {
703     LPSTREAM stream;
704     IPicture *pict;
705     HGLOBAL hglob;
706     LPBYTE *data;
707 
708     hglob = GlobalAlloc (0, sizeof(metafile));
709     data = GlobalLock(hglob);
710     memcpy(data, metafile, sizeof(metafile));
711 
712     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
713     /* Windows does not load simple metafiles */
714     ole_expect(pOleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
715 
716     IStream_Release(stream);
717 }
718 
719 static void test_enhmetafile(void)
720 {
721     OLE_HANDLE handle;
722     LPSTREAM stream;
723     IPicture *pict;
724     HGLOBAL hglob;
725     LPBYTE *data;
726     LONG cxy;
727     BOOL keep;
728     short type;
729 
730     hglob = GlobalAlloc (0, sizeof(enhmetafile));
731     data = GlobalLock(hglob);
732     memcpy(data, enhmetafile, sizeof(enhmetafile));
733 
734     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
735     ole_check(pOleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
736 
737     ole_check(IPicture_get_Handle(pict, &handle));
738     ok(handle != 0, "handle is null\n");
739 
740     ole_check(IPicture_get_Type(pict, &type));
741     expect_eq(type, PICTYPE_ENHMETAFILE, short, "%d");
742 
743     ole_check(IPicture_get_Height(pict, &cxy));
744     expect_eq(cxy, -23, LONG, "%d");
745 
746     ole_check(IPicture_get_Width(pict, &cxy));
747     expect_eq(cxy, -25, LONG, "%d");
748 
749     ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
750     todo_wine expect_eq(keep, FALSE, LONG, "%d");
751 
752     IPicture_Release(pict);
753     IStream_Release(stream);
754 }
755 
756 static HRESULT picture_render(IPicture *iface, HDC hdc, LONG x, LONG y, LONG cx, LONG cy,
757                               OLE_XPOS_HIMETRIC xSrc,
758                               OLE_YPOS_HIMETRIC ySrc,
759                               OLE_XSIZE_HIMETRIC cxSrc,
760                               OLE_YSIZE_HIMETRIC cySrc,
761                               const RECT *bounds)
762 {
763     VARIANT ret, args[10];
764     HRESULT hr, hr_disp;
765     DISPPARAMS params;
766     IDispatch *disp;
767     int i;
768 
769     hr = IPicture_Render(iface, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, bounds);
770 
771     IPicture_QueryInterface(iface, &IID_IDispatch, (void**)&disp);
772 
773     /* This is broken on 64 bits - accepted pointer argument type is still VT_I4 */
774     for (i = 0; i < ARRAY_SIZE(args); i++)
775         V_VT(&args[i]) = VT_I4;
776 
777     /* pack arguments and call */
778     V_INT_PTR(&args[0]) = (INT_PTR)bounds;
779     V_I4(&args[1]) = cySrc;
780     V_I4(&args[2]) = cxSrc;
781     V_I4(&args[3]) = ySrc;
782     V_I4(&args[4]) = xSrc;
783     V_I4(&args[5]) = cy;
784     V_I4(&args[6]) = cx;
785     V_I4(&args[7]) = y;
786     V_I4(&args[8]) = x;
787     V_I4(&args[9]) = HandleToLong(hdc);
788 
789     params.rgvarg = args;
790     params.rgdispidNamedArgs = NULL;
791     params.cArgs = 10;
792     params.cNamedArgs = 0;
793 
794     V_VT(&ret) = VT_EMPTY;
795     hr_disp = IDispatch_Invoke(disp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD,
796         &params, &ret, NULL, NULL);
797     ok(hr == hr_disp, "DISPID_PICT_RENDER returned wrong code, 0x%08x, expected 0x%08x\n",
798        hr_disp, hr);
799 
800     IDispatch_Release(disp);
801 
802     return hr;
803 }
804 
805 static void test_Render(void)
806 {
807     IPicture *pic;
808     HRESULT hres;
809     short type;
810     PICTDESC desc;
811     OLE_XSIZE_HIMETRIC pWidth;
812     OLE_YSIZE_HIMETRIC pHeight;
813     COLORREF result, expected;
814     HDC hdc = create_render_dc();
815 
816     /* test IPicture::Render return code on uninitialized picture */
817     hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
818     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
819     hres = IPicture_get_Type(pic, &type);
820     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
821     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
822     /* zero dimensions */
823     hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
824     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
825     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
826     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
827     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
828     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
829     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
830     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
831     hres = picture_render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
832     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
833     hres = picture_render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
834     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
835     hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
836     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
837     /* nonzero dimensions, PICTYPE_UNINITIALIZED */
838     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL);
839     ole_expect(hres, S_OK);
840     IPicture_Release(pic);
841 
842     desc.cbSizeofstruct = sizeof(PICTDESC);
843     desc.picType = PICTYPE_ICON;
844     desc.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
845     if(!desc.icon.hicon){
846         win_skip("LoadIcon failed. Skipping...\n");
847         delete_render_dc(hdc);
848         return;
849     }
850 
851     hres = OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (void **)&pic);
852     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
853     /* zero dimensions, PICTYPE_ICON */
854     hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
855     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
856     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
857     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
858     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
859     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
860     hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
861     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
862     hres = picture_render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
863     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
864     hres = picture_render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
865     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
866     hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
867     ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
868 
869     /* Check if target size and position is respected */
870     IPicture_get_Width(pic, &pWidth);
871     IPicture_get_Height(pic, &pHeight);
872 
873     SetPixelV(hdc, 0, 0, 0x00223344);
874     SetPixelV(hdc, 5, 5, 0x00223344);
875     SetPixelV(hdc, 10, 10, 0x00223344);
876     expected = GetPixel(hdc, 0, 0);
877 
878     hres = picture_render(pic, hdc, 1, 1, 9, 9, 0, pHeight, pWidth, -pHeight, NULL);
879     ole_expect(hres, S_OK);
880 
881     if(hres != S_OK) goto done;
882 
883     /* Evaluate the rendered Icon */
884     result = GetPixel(hdc, 0, 0);
885     ok(result == expected,
886        "Color at 0,0 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
887     result = GetPixel(hdc, 5, 5);
888     ok(result != expected,
889        "Color at 5,5 should have changed, but still was 0x%06X\n", expected);
890     result = GetPixel(hdc, 10, 10);
891     ok(result == expected,
892        "Color at 10,10 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
893 
894 done:
895     IPicture_Release(pic);
896     delete_render_dc(hdc);
897 }
898 
899 static void test_get_Attributes(void)
900 {
901     IPicture *pic;
902     HRESULT hres;
903     short type;
904     DWORD attr;
905 
906     hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
907     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
908     hres = IPicture_get_Type(pic, &type);
909     ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
910     ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
911 
912     hres = IPicture_get_Attributes(pic, NULL);
913     ole_expect(hres, E_POINTER);
914 
915     attr = 0xdeadbeef;
916     hres = IPicture_get_Attributes(pic, &attr);
917     ole_expect(hres, S_OK);
918     ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %d\n", attr);
919 
920     IPicture_Release(pic);
921 }
922 
923 static void test_get_Handle(void)
924 {
925     IPicture *pic;
926     HRESULT hres;
927 
928     hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
929     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
930     hres = IPicture_get_Handle(pic, NULL);
931     ole_expect(hres, E_POINTER);
932 
933     IPicture_Release(pic);
934 }
935 
936 static void test_get_Type(void)
937 {
938     IPicture *pic;
939     HRESULT hres;
940 
941     hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
942     ok(hres == S_OK, "Failed to create a picture, hr %#x.\n", hres);
943 
944     hres = IPicture_get_Type(pic, NULL);
945     ole_expect(hres, E_POINTER);
946 
947     IPicture_Release(pic);
948 }
949 
950 static void test_OleLoadPicturePath(void)
951 {
952     static WCHAR emptyW[] = {0};
953 
954     IPicture *pic;
955     HRESULT hres;
956     int i;
957     char temp_path[MAX_PATH];
958     char temp_file[MAX_PATH];
959     WCHAR temp_fileW[MAX_PATH + 5] = {'f','i','l','e',':','/','/','/'};
960     HANDLE file;
961     DWORD size;
962     WCHAR *ptr;
963     VARIANT var;
964 
965     const struct
966     {
967         LPOLESTR szURLorPath;
968         REFIID riid;
969         IPicture **pic;
970     } invalid_parameters[] =
971     {
972         {NULL,  NULL,          NULL},
973         {NULL,  NULL,          &pic},
974         {NULL,  &IID_IPicture, NULL},
975         {NULL,  &IID_IPicture, &pic},
976         {emptyW, NULL,          NULL},
977         {emptyW, &IID_IPicture, NULL},
978     };
979 
980     for (i = 0; i < ARRAY_SIZE(invalid_parameters); i++)
981     {
982         pic = (IPicture *)0xdeadbeef;
983         hres = OleLoadPicturePath(invalid_parameters[i].szURLorPath, NULL, 0, 0,
984                                   invalid_parameters[i].riid,
985                                   (void **)invalid_parameters[i].pic);
986         ok(hres == E_INVALIDARG,
987            "[%d] Expected OleLoadPicturePath to return E_INVALIDARG, got 0x%08x\n", i, hres);
988         ok(pic == (IPicture *)0xdeadbeef,
989            "[%d] Expected output pointer to be 0xdeadbeef, got %p\n", i, pic);
990     }
991 
992     pic = (IPicture *)0xdeadbeef;
993     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, NULL, (void **)&pic);
994     todo_wine
995     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
996        broken(hres == E_UNEXPECTED) || /* NT4 */
997        broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
998        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
999     ok(pic == NULL,
1000        "Expected the output interface pointer to be NULL, got %p\n", pic);
1001 
1002     pic = (IPicture *)0xdeadbeef;
1003     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
1004     todo_wine
1005     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
1006        broken(hres == E_UNEXPECTED) || /* NT4 */
1007        broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
1008        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
1009     ok(pic == NULL,
1010        "Expected the output interface pointer to be NULL, got %p\n", pic);
1011 
1012     /* Create a local temporary image file for testing. */
1013     GetTempPathA(sizeof(temp_path), temp_path);
1014     GetTempFileNameA(temp_path, "bmp", 0, temp_file);
1015     file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1016                        FILE_ATTRIBUTE_NORMAL, NULL);
1017     WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
1018     CloseHandle(file);
1019 
1020     MultiByteToWideChar(CP_ACP, 0, temp_file, -1, temp_fileW + 8, ARRAY_SIZE(temp_fileW) - 8);
1021 
1022     /* Try a normal DOS path. */
1023     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
1024     ok(hres == S_OK ||
1025        broken(hres == E_UNEXPECTED), /* NT4 */
1026        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
1027     if (pic)
1028         IPicture_Release(pic);
1029 
1030     VariantInit(&var);
1031     V_VT(&var) = VT_BSTR;
1032     V_BSTR(&var) = SysAllocString(temp_fileW + 8);
1033     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1034     ok(hres == S_OK, "OleLoadPictureFile error %#x\n", hres);
1035     IPicture_Release(pic);
1036     VariantClear(&var);
1037 
1038     /* Try a DOS path with tacked on "file:". */
1039     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
1040     ok(hres == S_OK ||
1041        broken(hres == E_UNEXPECTED), /* NT4 */
1042        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
1043     if (pic)
1044         IPicture_Release(pic);
1045 
1046     VariantInit(&var);
1047     V_VT(&var) = VT_BSTR;
1048     V_BSTR(&var) = SysAllocString(temp_fileW);
1049     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1050     ok(hres == CTL_E_PATHFILEACCESSERROR, "wrong error %#x\n", hres);
1051     VariantClear(&var);
1052 
1053     DeleteFileA(temp_file);
1054 
1055     /* Try with a nonexistent file. */
1056     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
1057     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
1058        broken(hres == E_UNEXPECTED) || /* NT4 */
1059        broken(hres == E_FAIL), /*Win2k */
1060        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
1061 
1062     VariantInit(&var);
1063     V_VT(&var) = VT_BSTR;
1064     V_BSTR(&var) = SysAllocString(temp_fileW + 8);
1065     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1066     ok(hres == CTL_E_FILENOTFOUND, "wrong error %#x\n", hres);
1067     VariantClear(&var);
1068 
1069     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
1070     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
1071        broken(hres == E_UNEXPECTED) || /* NT4 */
1072        broken(hres == E_FAIL), /* Win2k */
1073        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
1074 
1075     VariantInit(&var);
1076     V_VT(&var) = VT_BSTR;
1077     V_BSTR(&var) = SysAllocString(temp_fileW);
1078     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1079     ok(hres == CTL_E_PATHFILEACCESSERROR, "wrong error %#x\n", hres);
1080     VariantClear(&var);
1081 
1082     file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1083                        FILE_ATTRIBUTE_NORMAL, NULL);
1084     WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
1085     CloseHandle(file);
1086 
1087     /* Try a "file:" URL with slash separators. */
1088     ptr = temp_fileW + 8;
1089     while (*ptr)
1090     {
1091         if (*ptr == '\\')
1092             *ptr = '/';
1093         ptr++;
1094     }
1095 
1096     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
1097     ok(hres == S_OK ||
1098        broken(hres == E_UNEXPECTED), /* NT4 */
1099        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
1100     if (pic)
1101         IPicture_Release(pic);
1102 
1103     VariantInit(&var);
1104     V_VT(&var) = VT_BSTR;
1105     V_BSTR(&var) = SysAllocString(temp_fileW);
1106     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1107     ok(hres == CTL_E_PATHFILEACCESSERROR, "wrong error %#x\n", hres);
1108     VariantClear(&var);
1109 
1110     DeleteFileA(temp_file);
1111 
1112     /* Try with a nonexistent file. */
1113     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
1114     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
1115        broken(hres == E_UNEXPECTED) || /* NT4 */
1116        broken(hres == E_FAIL), /* Win2k */
1117        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
1118 
1119     VariantInit(&var);
1120     V_VT(&var) = VT_BSTR;
1121     V_BSTR(&var) = SysAllocString(temp_fileW);
1122     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1123     ok(hres == CTL_E_PATHFILEACCESSERROR, "wrong error %#x\n", hres);
1124     VariantClear(&var);
1125 
1126     VariantInit(&var);
1127     V_VT(&var) = VT_INT;
1128     V_INT(&var) = 762;
1129     hres = OleLoadPictureFile(var, (IDispatch **)&pic);
1130     ok(hres == CTL_E_FILENOTFOUND, "wrong error %#x\n", hres);
1131 
1132 if (0) /* crashes under Windows */
1133     hres = OleLoadPictureFile(var, NULL);
1134 }
1135 
1136 static void test_himetric(void)
1137 {
1138     static const BYTE bmp_bits[1024];
1139     OLE_XSIZE_HIMETRIC cx;
1140     OLE_YSIZE_HIMETRIC cy;
1141     IPicture *pic;
1142     PICTDESC desc;
1143     HBITMAP bmp;
1144     HRESULT hr;
1145     HICON icon;
1146     HDC hdc;
1147     INT d;
1148 
1149     desc.cbSizeofstruct = sizeof(desc);
1150     desc.picType = PICTYPE_BITMAP;
1151     desc.bmp.hpal = NULL;
1152 
1153     hdc = CreateCompatibleDC(0);
1154 
1155     bmp = CreateBitmap(1.9 * GetDeviceCaps(hdc, LOGPIXELSX),
1156                        1.9 * GetDeviceCaps(hdc, LOGPIXELSY), 1, 1, NULL);
1157 
1158     desc.bmp.hbitmap = bmp;
1159 
1160     /* size in himetric units reported rounded up to next integer value */
1161     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1162     ok(hr == S_OK, "got 0x%08x\n", hr);
1163 
1164     cx = 0;
1165     d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSX)), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
1166     hr = IPicture_get_Width(pic, &cx);
1167     ok(hr == S_OK, "got 0x%08x\n", hr);
1168     ok(cx == d, "got %d, expected %d\n", cx, d);
1169 
1170     cy = 0;
1171     d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSY)), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
1172     hr = IPicture_get_Height(pic, &cy);
1173     ok(hr == S_OK, "got 0x%08x\n", hr);
1174     ok(cy == d, "got %d, expected %d\n", cy, d);
1175 
1176     DeleteObject(bmp);
1177     IPicture_Release(pic);
1178 
1179     /* same thing with icon */
1180     icon = CreateIcon(NULL, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
1181                       1, 1, bmp_bits, bmp_bits);
1182     ok(icon != NULL, "failed to create icon\n");
1183 
1184     desc.picType = PICTYPE_ICON;
1185     desc.icon.hicon = icon;
1186 
1187     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1188     ok(hr == S_OK, "got 0x%08x\n", hr);
1189 
1190     cx = 0;
1191     d = MulDiv(GetSystemMetrics(SM_CXICON), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
1192     hr = IPicture_get_Width(pic, &cx);
1193     ok(hr == S_OK, "got 0x%08x\n", hr);
1194     ok(cx == d, "got %d, expected %d\n", cx, d);
1195 
1196     cy = 0;
1197     d = MulDiv(GetSystemMetrics(SM_CYICON), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
1198     hr = IPicture_get_Height(pic, &cy);
1199     ok(hr == S_OK, "got 0x%08x\n", hr);
1200     ok(cy == d, "got %d, expected %d\n", cy, d);
1201 
1202     IPicture_Release(pic);
1203     DestroyIcon(icon);
1204 
1205     DeleteDC(hdc);
1206 }
1207 
1208 static void test_load_save_bmp(void)
1209 {
1210     IPicture *pic;
1211     PICTDESC desc;
1212     short type;
1213     OLE_HANDLE handle;
1214     HGLOBAL hmem;
1215     DWORD *mem;
1216     IPersistStream *src_stream;
1217     IStream *dst_stream;
1218     LARGE_INTEGER offset;
1219     HRESULT hr;
1220     LONG size;
1221 
1222     desc.cbSizeofstruct = sizeof(desc);
1223     desc.picType = PICTYPE_BITMAP;
1224     desc.bmp.hpal = 0;
1225     desc.bmp.hbitmap = CreateBitmap(1, 1, 1, 1, NULL);
1226     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1227     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
1228 
1229     type = -1;
1230     hr = IPicture_get_Type(pic, &type);
1231     ok(hr == S_OK,"get_Type error %#8x\n", hr);
1232     ok(type == PICTYPE_BITMAP,"expected picture type PICTYPE_BITMAP, got %d\n", type);
1233 
1234     hr = IPicture_get_Handle(pic, &handle);
1235     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1236     ok(IntToPtr(handle) == desc.bmp.hbitmap, "get_Handle returned wrong handle %#x\n", handle);
1237 
1238     hmem = GlobalAlloc(GMEM_ZEROINIT, 4096);
1239     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
1240     ok(hr == S_OK, "createstreamonhglobal error %#x\n", hr);
1241 
1242     size = -1;
1243     hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
1244     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1245     ok(size == 66, "expected 66, got %d\n", size);
1246     mem = GlobalLock(hmem);
1247     ok(!memcmp(&mem[0], "BM", 2), "got wrong bmp header %04x\n", mem[0]);
1248     GlobalUnlock(hmem);
1249 
1250     size = -1;
1251     hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
1252     ok(hr == E_FAIL, "expected E_FAIL, got %#x\n", hr);
1253     ok(size == -1, "expected -1, got %d\n", size);
1254 
1255     offset.QuadPart = 0;
1256     hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
1257     ok(hr == S_OK, "IStream_Seek %#x\n", hr);
1258 
1259     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
1260     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1261 
1262     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
1263     ok(hr == S_OK, "Save error %#x\n", hr);
1264 
1265     IPersistStream_Release(src_stream);
1266     IStream_Release(dst_stream);
1267 
1268     mem = GlobalLock(hmem);
1269     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
1270     ok(mem[1] == 66, "expected stream size 66, got %u\n", mem[1]);
1271     ok(!memcmp(&mem[2], "BM", 2), "got wrong bmp header %04x\n", mem[2]);
1272 
1273     GlobalUnlock(hmem);
1274     GlobalFree(hmem);
1275 
1276     DeleteObject(desc.bmp.hbitmap);
1277     IPicture_Release(pic);
1278 }
1279 
1280 static void test_load_save_icon(void)
1281 {
1282     IPicture *pic;
1283     PICTDESC desc;
1284     short type;
1285     OLE_HANDLE handle;
1286     HGLOBAL hmem;
1287     DWORD *mem;
1288     IPersistStream *src_stream;
1289     IStream *dst_stream;
1290     LARGE_INTEGER offset;
1291     HRESULT hr;
1292     LONG size;
1293 
1294     desc.cbSizeofstruct = sizeof(desc);
1295     desc.picType = PICTYPE_ICON;
1296     desc.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
1297     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1298     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
1299 
1300     type = -1;
1301     hr = IPicture_get_Type(pic, &type);
1302     ok(hr == S_OK,"get_Type error %#8x\n", hr);
1303     ok(type == PICTYPE_ICON,"expected picture type PICTYPE_ICON, got %d\n", type);
1304 
1305     hr = IPicture_get_Handle(pic, &handle);
1306     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1307     ok(IntToPtr(handle) == desc.icon.hicon, "get_Handle returned wrong handle %#x\n", handle);
1308 
1309     hmem = GlobalAlloc(GMEM_ZEROINIT, 8192);
1310     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
1311     ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
1312 
1313     size = -1;
1314     hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
1315     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1316 todo_wine
1317     ok(size == 766, "expected 766, got %d\n", size);
1318     mem = GlobalLock(hmem);
1319     ok(mem[0] == 0x00010000, "got wrong icon header %04x\n", mem[0]);
1320     GlobalUnlock(hmem);
1321 
1322     size = -1;
1323     hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
1324     ok(hr == E_FAIL, "expected E_FAIL, got %#x\n", hr);
1325     ok(size == -1, "expected -1, got %d\n", size);
1326 
1327     offset.QuadPart = 0;
1328     hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
1329     ok(hr == S_OK, "IStream_Seek %#x\n", hr);
1330 
1331     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
1332     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1333 
1334     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
1335     ok(hr == S_OK, "Saveerror %#x\n", hr);
1336 
1337     IPersistStream_Release(src_stream);
1338     IStream_Release(dst_stream);
1339 
1340     mem = GlobalLock(hmem);
1341     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
1342 todo_wine
1343     ok(mem[1] == 766, "expected stream size 766, got %u\n", mem[1]);
1344     ok(mem[2] == 0x00010000, "got wrong icon header %04x\n", mem[2]);
1345 
1346     GlobalUnlock(hmem);
1347     GlobalFree(hmem);
1348 
1349     DestroyIcon(desc.icon.hicon);
1350     IPicture_Release(pic);
1351 }
1352 
1353 static void test_load_save_empty_picture(void)
1354 {
1355     IPicture *pic;
1356     PICTDESC desc;
1357     short type;
1358     OLE_HANDLE handle;
1359     HGLOBAL hmem;
1360     DWORD *mem;
1361     IPersistStream *src_stream;
1362     IStream *dst_stream, *stream;
1363     LARGE_INTEGER offset;
1364     HRESULT hr;
1365     LONG size;
1366 
1367     memset(&pic, 0, sizeof(pic));
1368     desc.cbSizeofstruct = sizeof(desc);
1369     desc.picType = PICTYPE_NONE;
1370     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void **)&pic);
1371     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
1372 
1373     type = -1;
1374     hr = IPicture_get_Type(pic, &type);
1375     ok(hr == S_OK, "get_Type error %#x\n", hr);
1376     ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
1377 
1378     handle = (OLE_HANDLE)0xdeadbeef;
1379     hr = IPicture_get_Handle(pic, &handle);
1380     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1381     ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
1382 
1383     hmem = GlobalAlloc(GMEM_ZEROINIT, 4096);
1384     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
1385     ok(hr == S_OK, "createstreamonhglobal error %#x\n", hr);
1386 
1387     size = -1;
1388     hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
1389     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1390     ok(size == -1, "expected -1, got %d\n", size);
1391 
1392     size = -1;
1393     hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
1394     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1395     ok(size == -1, "expected -1, got %d\n", size);
1396 
1397     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
1398     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1399 
1400     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
1401     ok(hr == S_OK, "Save error %#x\n", hr);
1402 
1403     mem = GlobalLock(hmem);
1404     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
1405     ok(mem[1] == 0, "expected stream size 0, got %u\n", mem[1]);
1406     GlobalUnlock(hmem);
1407 
1408     IPersistStream_Release(src_stream);
1409     IPicture_Release(pic);
1410 
1411     /* first with statable and seekable stream */
1412     offset.QuadPart = 0;
1413     hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
1414     ok(hr == S_OK, "IStream_Seek %#x\n", hr);
1415 
1416     pic = NULL;
1417     hr = pOleLoadPicture(dst_stream, 0, FALSE, &IID_IPicture, (void **)&pic);
1418     ok(hr == S_OK, "OleLoadPicture error %#x\n", hr);
1419     ok(pic != NULL,"picture should not be not NULL\n");
1420     if (pic != NULL)
1421     {
1422         type = -1;
1423         hr = IPicture_get_Type(pic, &type);
1424         ok(hr == S_OK,"get_Type error %#8x\n", hr);
1425         ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
1426 
1427         handle = (OLE_HANDLE)0xdeadbeef;
1428         hr = IPicture_get_Handle(pic, &handle);
1429         ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1430         ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
1431 
1432         IPicture_Release(pic);
1433     }
1434     IStream_Release(dst_stream);
1435 
1436     /* again with non-statable and non-seekable stream */
1437     stream = NoStatStream_Construct(hmem);
1438     ok(stream != NULL, "failed to create empty image stream\n");
1439 
1440     pic = NULL;
1441     hr = pOleLoadPicture(stream, 0, FALSE, &IID_IPicture, (void **)&pic);
1442     ok(hr == S_OK, "OleLoadPicture error %#x\n", hr);
1443     ok(pic != NULL,"picture should not be not NULL\n");
1444     if (pic != NULL)
1445     {
1446         type = -1;
1447         hr = IPicture_get_Type(pic, &type);
1448         ok(hr == S_OK,"get_Type error %#8x\n", hr);
1449         ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
1450 
1451         handle = (OLE_HANDLE)0xdeadbeef;
1452         hr = IPicture_get_Handle(pic, &handle);
1453         ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1454         ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
1455 
1456         IPicture_Release(pic);
1457     }
1458     /* Non-statable impl always deletes on release */
1459     IStream_Release(stream);
1460 }
1461 
1462 static void test_load_save_emf(void)
1463 {
1464     HDC hdc;
1465     IPicture *pic;
1466     PICTDESC desc;
1467     short type;
1468     OLE_HANDLE handle;
1469     HGLOBAL hmem;
1470     DWORD *mem;
1471     ENHMETAHEADER *emh;
1472     IPersistStream *src_stream;
1473     IStream *dst_stream;
1474     LARGE_INTEGER offset;
1475     HRESULT hr;
1476     LONG size;
1477 
1478     hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
1479     ok(hdc != 0, "CreateEnhMetaFileA failed\n");
1480 
1481     desc.cbSizeofstruct = sizeof(desc);
1482     desc.picType = PICTYPE_ENHMETAFILE;
1483     desc.emf.hemf = CloseEnhMetaFile(hdc);
1484     ok(desc.emf.hemf != 0, "CloseEnhMetaFile failed\n");
1485     hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
1486     ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
1487 
1488     type = -1;
1489     hr = IPicture_get_Type(pic, &type);
1490     ok(hr == S_OK,"get_Type error %#8x\n", hr);
1491     ok(type == PICTYPE_ENHMETAFILE,"expected PICTYPE_ENHMETAFILE, got %d\n", type);
1492 
1493     hr = IPicture_get_Handle(pic, &handle);
1494     ok(hr == S_OK,"get_Handle error %#8x\n", hr);
1495     ok(IntToPtr(handle) == desc.emf.hemf, "get_Handle returned wrong handle %#x\n", handle);
1496 
1497     hmem = GlobalAlloc(GMEM_MOVEABLE, 0);
1498     hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
1499     ok(hr == S_OK, "createstreamonhglobal error %#x\n", hr);
1500 
1501     size = -1;
1502     hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
1503     ok(hr == S_OK, "IPicture_SaveasFile error %#x\n", hr);
1504     ok(size == 128, "expected 128, got %d\n", size);
1505     emh = GlobalLock(hmem);
1506 if (size)
1507 {
1508     ok(emh->iType == EMR_HEADER, "wrong iType %04x\n", emh->iType);
1509     ok(emh->dSignature == ENHMETA_SIGNATURE, "wrong dSignature %08x\n", emh->dSignature);
1510 }
1511     GlobalUnlock(hmem);
1512 
1513     size = -1;
1514     hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
1515     ok(hr == E_FAIL, "expected E_FAIL, got %#x\n", hr);
1516     ok(size == -1, "expected -1, got %d\n", size);
1517 
1518     offset.QuadPart = 0;
1519     hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
1520     ok(hr == S_OK, "IStream_Seek %#x\n", hr);
1521 
1522     hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
1523     ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1524 
1525     hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
1526     ok(hr == S_OK, "Save error %#x\n", hr);
1527 
1528     IPersistStream_Release(src_stream);
1529     IStream_Release(dst_stream);
1530 
1531     mem = GlobalLock(hmem);
1532     ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
1533     ok(mem[1] == 128, "expected 128, got %u\n", mem[1]);
1534     emh = (ENHMETAHEADER *)(mem + 2);
1535     ok(emh->iType == EMR_HEADER, "wrong iType %04x\n", emh->iType);
1536     ok(emh->dSignature == ENHMETA_SIGNATURE, "wrong dSignature %08x\n", emh->dSignature);
1537 
1538     GlobalUnlock(hmem);
1539     GlobalFree(hmem);
1540 
1541     DeleteEnhMetaFile(desc.emf.hemf);
1542     IPicture_Release(pic);
1543 }
1544 
1545 START_TEST(olepicture)
1546 {
1547     hOleaut32 = GetModuleHandleA("oleaut32.dll");
1548     pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
1549     pOleLoadPictureEx = (void*)GetProcAddress(hOleaut32, "OleLoadPictureEx");
1550     if (!pOleLoadPicture)
1551     {
1552         win_skip("OleLoadPicture is not available\n");
1553         return;
1554     }
1555 
1556     /* Test regular 1x1 pixel images of gif, jpg, bmp type */
1557     test_pic(gifimage, sizeof(gifimage));
1558     test_pic(jpgimage, sizeof(jpgimage));
1559     test_pic(bmpimage, sizeof(bmpimage));
1560     test_pic(bmpimage_rle8, sizeof(bmpimage_rle8));
1561     test_pic(gif4pixel, sizeof(gif4pixel));
1562     /* FIXME: No PNG support in Windows... */
1563     if (0) test_pic(pngimage, sizeof(pngimage));
1564     test_empty_image();
1565     test_empty_image_2();
1566     if (pOleLoadPictureEx)
1567     {
1568         test_apm();
1569         test_metafile();
1570         test_enhmetafile();
1571     }
1572     else
1573         win_skip("OleLoadPictureEx is not available\n");
1574     test_Invoke();
1575     test_OleCreatePictureIndirect();
1576     test_Render();
1577     test_get_Attributes();
1578     test_get_Handle();
1579     test_get_Type();
1580     test_OleLoadPicturePath();
1581     test_himetric();
1582     test_load_save_bmp();
1583     test_load_save_icon();
1584     test_load_save_empty_picture();
1585     test_load_save_emf();
1586 }
1587 
1588 
1589 /* Helper functions only ... */
1590 
1591 
1592 static inline NoStatStreamImpl *impl_from_IStream(IStream *iface)
1593 {
1594   return CONTAINING_RECORD(iface, NoStatStreamImpl, IStream_iface);
1595 }
1596 
1597 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
1598 {
1599   GlobalFree(This->supportHandle);
1600   This->supportHandle=0;
1601   HeapFree(GetProcessHeap(), 0, This);
1602 }
1603 
1604 static ULONG WINAPI NoStatStreamImpl_AddRef(
1605 		IStream* iface)
1606 {
1607   NoStatStreamImpl* const This = impl_from_IStream(iface);
1608   return InterlockedIncrement(&This->ref);
1609 }
1610 
1611 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
1612 		  IStream*     iface,
1613 		  REFIID         riid,	      /* [in] */
1614 		  void**         ppvObject)   /* [iid_is][out] */
1615 {
1616   NoStatStreamImpl* const This = impl_from_IStream(iface);
1617   if (ppvObject==0) return E_INVALIDARG;
1618   *ppvObject = 0;
1619 
1620   if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IStream, riid))
1621     *ppvObject = &This->IStream_iface;
1622 
1623   if ((*ppvObject)==0)
1624     return E_NOINTERFACE;
1625   NoStatStreamImpl_AddRef(iface);
1626   return S_OK;
1627 }
1628 
1629 static ULONG WINAPI NoStatStreamImpl_Release(
1630 		IStream* iface)
1631 {
1632   NoStatStreamImpl* const This = impl_from_IStream(iface);
1633   ULONG newRef = InterlockedDecrement(&This->ref);
1634   if (newRef==0)
1635     NoStatStreamImpl_Destroy(This);
1636   return newRef;
1637 }
1638 
1639 static HRESULT WINAPI NoStatStreamImpl_Read(
1640 		  IStream*     iface,
1641 		  void*          pv,        /* [length_is][size_is][out] */
1642 		  ULONG          cb,        /* [in] */
1643 		  ULONG*         pcbRead)   /* [out] */
1644 {
1645   NoStatStreamImpl* const This = impl_from_IStream(iface);
1646   void* supportBuffer;
1647   ULONG bytesReadBuffer;
1648   ULONG bytesToReadFromBuffer;
1649 
1650   if (pcbRead==0)
1651     pcbRead = &bytesReadBuffer;
1652   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
1653   supportBuffer = GlobalLock(This->supportHandle);
1654   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
1655   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
1656   *pcbRead = bytesToReadFromBuffer;
1657   GlobalUnlock(This->supportHandle);
1658   if(*pcbRead == cb)
1659     return S_OK;
1660   return S_FALSE;
1661 }
1662 
1663 static HRESULT WINAPI NoStatStreamImpl_Write(
1664 	          IStream*     iface,
1665 		  const void*    pv,          /* [size_is][in] */
1666 		  ULONG          cb,          /* [in] */
1667 		  ULONG*         pcbWritten)  /* [out] */
1668 {
1669   NoStatStreamImpl* const This = impl_from_IStream(iface);
1670   void*          supportBuffer;
1671   ULARGE_INTEGER newSize;
1672   ULONG          bytesWritten = 0;
1673 
1674   if (pcbWritten == 0)
1675     pcbWritten = &bytesWritten;
1676   if (cb == 0)
1677     return S_OK;
1678   newSize.u.HighPart = 0;
1679   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
1680   if (newSize.u.LowPart > This->streamSize.u.LowPart)
1681    IStream_SetSize(iface, newSize);
1682 
1683   supportBuffer = GlobalLock(This->supportHandle);
1684   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
1685   This->currentPosition.u.LowPart+=cb;
1686   *pcbWritten = cb;
1687   GlobalUnlock(This->supportHandle);
1688   return S_OK;
1689 }
1690 
1691 static HRESULT WINAPI NoStatStreamImpl_Seek(
1692 		  IStream*      iface,
1693 		  LARGE_INTEGER   dlibMove,         /* [in] */
1694 		  DWORD           dwOrigin,         /* [in] */
1695 		  ULARGE_INTEGER* plibNewPosition) /* [out] */
1696 {
1697   NoStatStreamImpl* const This = impl_from_IStream(iface);
1698   ULARGE_INTEGER newPosition;
1699   switch (dwOrigin)
1700   {
1701     case STREAM_SEEK_SET:
1702       newPosition.u.HighPart = 0;
1703       newPosition.u.LowPart = 0;
1704       break;
1705     case STREAM_SEEK_CUR:
1706       newPosition = This->currentPosition;
1707       break;
1708     case STREAM_SEEK_END:
1709       newPosition = This->streamSize;
1710       break;
1711     default:
1712       return STG_E_INVALIDFUNCTION;
1713   }
1714   if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
1715       return STG_E_INVALIDFUNCTION;
1716   newPosition.QuadPart += dlibMove.QuadPart;
1717   if (plibNewPosition) *plibNewPosition = newPosition;
1718   This->currentPosition = newPosition;
1719   return S_OK;
1720 }
1721 
1722 static HRESULT WINAPI NoStatStreamImpl_SetSize(
1723 				     IStream*      iface,
1724 				     ULARGE_INTEGER  libNewSize)   /* [in] */
1725 {
1726   NoStatStreamImpl* const This = impl_from_IStream(iface);
1727   HGLOBAL supportHandle;
1728   if (libNewSize.u.HighPart != 0)
1729     return STG_E_INVALIDFUNCTION;
1730   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
1731     return S_OK;
1732   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
1733   if (supportHandle == 0)
1734     return STG_E_MEDIUMFULL;
1735   This->supportHandle = supportHandle;
1736   This->streamSize.u.LowPart = libNewSize.u.LowPart;
1737   return S_OK;
1738 }
1739 
1740 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
1741 				    IStream*      iface,
1742 				    IStream*      pstm,         /* [unique][in] */
1743 				    ULARGE_INTEGER  cb,           /* [in] */
1744 				    ULARGE_INTEGER* pcbRead,      /* [out] */
1745 				    ULARGE_INTEGER* pcbWritten)   /* [out] */
1746 {
1747   HRESULT        hr = S_OK;
1748   BYTE           tmpBuffer[128];
1749   ULONG          bytesRead, bytesWritten, copySize;
1750   ULARGE_INTEGER totalBytesRead;
1751   ULARGE_INTEGER totalBytesWritten;
1752 
1753   if ( pstm == 0 )
1754     return STG_E_INVALIDPOINTER;
1755   totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
1756   totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
1757 
1758   while ( cb.u.LowPart > 0 )
1759   {
1760     if ( cb.u.LowPart >= 128 )
1761       copySize = 128;
1762     else
1763       copySize = cb.u.LowPart;
1764     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1765     totalBytesRead.u.LowPart += bytesRead;
1766     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1767     totalBytesWritten.u.LowPart += bytesWritten;
1768     if (bytesRead != bytesWritten)
1769     {
1770       hr = STG_E_MEDIUMFULL;
1771       break;
1772     }
1773     if (bytesRead!=copySize)
1774       cb.u.LowPart = 0;
1775     else
1776       cb.u.LowPart -= bytesRead;
1777   }
1778   if (pcbRead)
1779   {
1780     pcbRead->u.LowPart = totalBytesRead.u.LowPart;
1781     pcbRead->u.HighPart = totalBytesRead.u.HighPart;
1782   }
1783 
1784   if (pcbWritten)
1785   {
1786     pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
1787     pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
1788   }
1789   return hr;
1790 }
1791 
1792 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
1793 {
1794   return S_OK;
1795 }
1796 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
1797 
1798 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
1799 		  IStream*       iface,
1800 		  ULARGE_INTEGER libOffset,   /* [in] */
1801 		  ULARGE_INTEGER cb,          /* [in] */
1802 		  DWORD          dwLockType)  /* [in] */
1803 {
1804   return S_OK;
1805 }
1806 
1807 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
1808 		  IStream*       iface,
1809 		  ULARGE_INTEGER libOffset,   /* [in] */
1810 		  ULARGE_INTEGER cb,          /* [in] */
1811 		  DWORD          dwLockType)  /* [in] */
1812 {
1813   return S_OK;
1814 }
1815 
1816 static HRESULT WINAPI NoStatStreamImpl_Stat(
1817 		  IStream*     iface,
1818 		  STATSTG*     pstatstg,     /* [out] */
1819 		  DWORD        grfStatFlag)  /* [in] */
1820 {
1821   return E_NOTIMPL;
1822 }
1823 
1824 static HRESULT WINAPI NoStatStreamImpl_Clone(
1825 		  IStream*     iface,
1826 		  IStream**    ppstm) /* [out] */
1827 {
1828   return E_NOTIMPL;
1829 }
1830 static const IStreamVtbl NoStatStreamImpl_Vtbl;
1831 
1832 /*
1833     Build an object that implements IStream, without IStream_Stat capabilities.
1834     Receives a memory handle with data buffer. If memory handle is non-null,
1835     it is assumed to be unlocked, otherwise an internal memory handle is allocated.
1836     In any case the object takes ownership of memory handle and will free it on
1837     object release.
1838  */
1839 static IStream* NoStatStream_Construct(HGLOBAL hGlobal)
1840 {
1841   NoStatStreamImpl* newStream;
1842 
1843   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
1844   if (newStream!=0)
1845   {
1846     newStream->IStream_iface.lpVtbl = &NoStatStreamImpl_Vtbl;
1847     newStream->ref    = 1;
1848     newStream->supportHandle = hGlobal;
1849 
1850     if (!newStream->supportHandle)
1851       newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
1852 					     GMEM_SHARE, 0);
1853     newStream->currentPosition.u.HighPart = 0;
1854     newStream->currentPosition.u.LowPart = 0;
1855     newStream->streamSize.u.HighPart = 0;
1856     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
1857   }
1858   return &newStream->IStream_iface;
1859 }
1860 
1861 
1862 static const IStreamVtbl NoStatStreamImpl_Vtbl =
1863 {
1864     NoStatStreamImpl_QueryInterface,
1865     NoStatStreamImpl_AddRef,
1866     NoStatStreamImpl_Release,
1867     NoStatStreamImpl_Read,
1868     NoStatStreamImpl_Write,
1869     NoStatStreamImpl_Seek,
1870     NoStatStreamImpl_SetSize,
1871     NoStatStreamImpl_CopyTo,
1872     NoStatStreamImpl_Commit,
1873     NoStatStreamImpl_Revert,
1874     NoStatStreamImpl_LockRegion,
1875     NoStatStreamImpl_UnlockRegion,
1876     NoStatStreamImpl_Stat,
1877     NoStatStreamImpl_Clone
1878 };
1879