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