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