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