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