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