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