1 /*
2 * OLEPICTURE test program
3 *
4 * Copyright 2005 Marcus Meissner
5 *
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <math.h>
25 #include <float.h>
26
27 #define COBJMACROS
28 #define CONST_VTABLE
29 #define NONAMELESSUNION
30
31 #include "wine/test.h"
32 #include <windef.h>
33 #include <winbase.h>
34 #include <winuser.h>
35 #include <wingdi.h>
36 #include <winnls.h>
37 #include <winerror.h>
38 #include <winnt.h>
39
40 #include <urlmon.h>
41 #include <wtypes.h>
42 #include <olectl.h>
43 #include <objidl.h>
44
45 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
46
47 #define ole_expect(expr, expect) { \
48 HRESULT r = expr; \
49 ok(r == (expect), #expr " returned %x, expected %s (%x)\n", r, #expect, expect); \
50 }
51
52 #define ole_check(expr) ole_expect(expr, S_OK);
53
54 static HMODULE hOleaut32;
55
56 static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);
57 static HRESULT (WINAPI *pOleLoadPictureEx)(LPSTREAM,LONG,BOOL,REFIID,DWORD,DWORD,DWORD,LPVOID*);
58 static HRESULT (WINAPI *pOleCreatePictureIndirect)(PICTDESC*,REFIID,BOOL,LPVOID*);
59
60 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
61
62 /* 1x1 pixel gif */
63 static const unsigned char gifimage[35] = {
64 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
65 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
66 0x01,0x00,0x3b
67 };
68
69 /* 1x1 pixel jpg */
70 static const unsigned char jpgimage[285] = {
71 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
72 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
73 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
74 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
75 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
76 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
77 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
78 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
79 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
80 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
81 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
82 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
83 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
84 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
85 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
86 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
87 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
88 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
89 };
90
91 /* 1x1 pixel png */
92 static const unsigned char pngimage[285] = {
93 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
94 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
95 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
96 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
97 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
98 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
99 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
100 };
101
102 /* 1x1 pixel bmp */
103 static const unsigned char bmpimage[66] = {
104 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
105 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
106 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
107 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
108 0x00,0x00
109 };
110
111 /* 2x2 pixel gif */
112 static const unsigned char gif4pixel[42] = {
113 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
114 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
115 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
116 };
117
118 /* APM with an empty metafile with some padding zeros - looks like under Window the
119 * metafile data should be at least 20 bytes */
120 static const unsigned char apmdata[] = {
121 0xd7,0xcd,0xc6,0x9a, 0x00,0x00,0x00,0x00, 0x00,0x00,0xee,0x02, 0xb1,0x03,0xa0,0x05,
122 0x00,0x00,0x00,0x00, 0xee,0x53,0x01,0x00, 0x09,0x00,0x00,0x03, 0x13,0x00,0x00,0x00,
123 0x01,0x00,0x05,0x00, 0x00,0x00,0x00,0x00, 0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
124 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
125 };
126
127 /* MF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
128 static const unsigned char metafile[] = {
129 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
132 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
133 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
134 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
135 0x00, 0x00
136 };
137
138 /* EMF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
139 static const unsigned char enhmetafile[] = {
140 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
145 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
146 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
147 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
150 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
153 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
154 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
155 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
157 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
159 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
160 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
163 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
164 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
165 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
166 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
167 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
168 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
170 0x14, 0x00, 0x00, 0x00
171 };
172
173
174 typedef struct NoStatStreamImpl
175 {
176 IStream IStream_iface;
177 LONG ref;
178
179 HGLOBAL supportHandle;
180 ULARGE_INTEGER streamSize;
181 ULARGE_INTEGER currentPosition;
182 } NoStatStreamImpl;
183
184 static IStream* NoStatStream_Construct(HGLOBAL hGlobal);
185
186 static void
187 test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
188 {
189 IPicture* pic = NULL;
190 HRESULT hres;
191 LPVOID pvObj = NULL;
192 OLE_HANDLE handle, hPal;
193 OLE_XSIZE_HIMETRIC width;
194 OLE_YSIZE_HIMETRIC height;
195 short type;
196 DWORD attr;
197 ULONG res;
198
199 pvObj = NULL;
200 hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
201 pic = pvObj;
202
203 ok(hres == S_OK,"OLP (NULL,..) does not return 0, but 0x%08x\n",hres);
204 ok(pic != NULL,"OLP (NULL,..) returns NULL, instead of !NULL\n");
205 if (pic == NULL)
206 return;
207
208 pvObj = NULL;
209 hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);
210
211 ok(hres == S_OK,"IPicture_QI does not return S_OK, but 0x%08x\n", hres);
212 ok(pvObj != NULL,"IPicture_QI does return NULL, instead of a ptr\n");
213
214 IPicture_Release ((IPicture*)pvObj);
215
216 handle = 0;
217 hres = IPicture_get_Handle (pic, &handle);
218 ok(hres == S_OK,"IPicture_get_Handle does not return S_OK, but 0x%08x\n", hres);
219 ok(handle != 0, "IPicture_get_Handle returns a NULL handle, but it should be non NULL\n");
220
221 if (handle)
222 {
223 BITMAP bmp;
224 GetObject(UlongToHandle(handle), sizeof(BITMAP), &bmp);
225 todo_wine ok(bmp.bmBits != 0, "not a dib\n");
226 }
227
228 width = 0;
229 hres = IPicture_get_Width (pic, &width);
230 ok(hres == S_OK,"IPicture_get_Width does not return S_OK, but 0x%08x\n", hres);
231 ok(width != 0, "IPicture_get_Width returns 0, but it should not be 0.\n");
232
233 height = 0;
234 hres = IPicture_get_Height (pic, &height);
235 ok(hres == S_OK,"IPicture_get_Height does not return S_OK, but 0x%08x\n", hres);
236 ok(height != 0, "IPicture_get_Height returns 0, but it should not be 0.\n");
237
238 type = 0;
239 hres = IPicture_get_Type (pic, &type);
240 ok(hres == S_OK,"IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
241 ok(type == PICTYPE_BITMAP, "IPicture_get_Type returns %d, but it should be PICTYPE_BITMAP(%d).\n", type, PICTYPE_BITMAP);
242
243 attr = 0;
244 hres = IPicture_get_Attributes (pic, &attr);
245 ok(hres == S_OK,"IPicture_get_Attributes does not return S_OK, but 0x%08x\n", hres);
246 ok(attr == 0, "IPicture_get_Attributes returns %d, but it should be 0.\n", attr);
247
248 hPal = 0;
249 hres = IPicture_get_hPal (pic, &hPal);
250 ok(hres == S_OK,"IPicture_get_hPal does not return S_OK, but 0x%08x\n", hres);
251 /* a single pixel b/w image has no palette */
252 ok(hPal == 0, "IPicture_get_hPal returns %d, but it should be 0.\n", hPal);
253
254 res = IPicture_Release (pic);
255 ok (res == 0, "refcount after release is %d, but should be 0?\n", res);
256 }
257
258 static void
259 test_pic(const unsigned char *imgdata, unsigned int imgsize)
260 {
261 LPSTREAM stream;
262 HGLOBAL hglob;
263 LPBYTE data;
264 HRESULT hres;
265 LARGE_INTEGER seekto;
266 ULARGE_INTEGER newpos1;
267 DWORD * header;
268 unsigned int i,j;
269
270 /* Let the fun begin */
271 hglob = GlobalAlloc (0, imgsize);
272 data = GlobalLock (hglob);
273 memcpy(data, imgdata, imgsize);
274 GlobalUnlock(hglob); data = NULL;
275
276 hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
277 ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
278
279 memset(&seekto,0,sizeof(seekto));
280 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
281 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
282 test_pic_with_stream(stream, imgsize);
283
284 IStream_Release(stream);
285
286 /* again with Non Statable and Non Seekable stream */
287 stream = NoStatStream_Construct(hglob);
288 hglob = 0; /* Non-statable impl always deletes on release */
289 test_pic_with_stream(stream, 0);
290
291 IStream_Release(stream);
292 for (i = 1; i <= 8; i++) {
293 /* more fun!!! */
294 hglob = GlobalAlloc (0, imgsize + i * (2 * sizeof(DWORD)));
295 data = GlobalLock (hglob);
296 header = (DWORD *)data;
297
298 /* multiple copies of header */
299 memcpy(data,"lt\0\0",4);
300 header[1] = imgsize;
301 for (j = 2; j <= i; j++) {
302 memcpy(&(header[2 * (j - 1)]), header, 2 * sizeof(DWORD));
303 }
304 memcpy(data + i * (2 * sizeof(DWORD)), imgdata, imgsize);
305 GlobalUnlock(hglob); data = NULL;
306
307 hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
308 ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
309
310 memset(&seekto,0,sizeof(seekto));
311 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
312 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
313 test_pic_with_stream(stream, imgsize);
314
315 IStream_Release(stream);
316
317 /* again with Non Statable and Non Seekable stream */
318 stream = NoStatStream_Construct(hglob);
319 hglob = 0; /* Non-statable impl always deletes on release */
320 test_pic_with_stream(stream, 0);
321
322 IStream_Release(stream);
323 }
324 }
325
326 static void test_empty_image(void) {
327 LPBYTE data;
328 LPSTREAM stream;
329 IPicture* pic = NULL;
330 HRESULT hres;
331 LPVOID pvObj = NULL;
332 HGLOBAL hglob;
333 OLE_HANDLE handle;
334 ULARGE_INTEGER newpos1;
335 LARGE_INTEGER seekto;
336 short type;
337 DWORD attr;
338
339 /* Empty image. Happens occasionally in VB programs. */
340 hglob = GlobalAlloc (0, 8);
341 data = GlobalLock (hglob);
342 memcpy(data,"lt\0\0",4);
343 ((DWORD*)data)[1] = 0;
344 hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
345 ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
346
347 memset(&seekto,0,sizeof(seekto));
348 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
349 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
350
351 pvObj = NULL;
352 hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
353 pic = pvObj;
354 ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
355 ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
356
357 hres = IPicture_get_Type (pic, &type);
358 ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
359 ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
360
361 attr = 0xdeadbeef;
362 hres = IPicture_get_Attributes (pic, &attr);
363 ok (hres == S_OK,"empty picture get attributes failed with hres 0x%08x\n", hres);
364 ok (attr == 0,"attr is %d, but should be 0\n", attr);
365
366 hres = IPicture_get_Handle (pic, &handle);
367 ok (hres == S_OK,"empty picture get handle failed with hres 0x%08x\n", hres);
368 ok (handle == 0, "empty picture get handle did not return 0, but 0x%08x\n", handle);
369 IPicture_Release (pic);
370 IStream_Release (stream);
371 }
372
373 static void test_empty_image_2(void) {
374 LPBYTE data;
375 LPSTREAM stream;
376 IPicture* pic = NULL;
377 HRESULT hres;
378 LPVOID pvObj = NULL;
379 HGLOBAL hglob;
380 ULARGE_INTEGER newpos1;
381 LARGE_INTEGER seekto;
382 short type;
383
384 /* Empty image at random stream position. */
385 hglob = GlobalAlloc (0, 200);
386 data = GlobalLock (hglob);
387 data += 42;
388 memcpy(data,"lt\0\0",4);
389 ((DWORD*)data)[1] = 0;
390 hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
391 ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
392
393 memset(&seekto,0,sizeof(seekto));
394 seekto.u.LowPart = 42;
395 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
396 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
397
398 pvObj = NULL;
399 hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
400 pic = pvObj;
401 ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
402 ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
403
404 hres = IPicture_get_Type (pic, &type);
405 ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
406 ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
407
408 IPicture_Release (pic);
409 IStream_Release (stream);
410 }
411
412 static void test_Invoke(void)
413 {
414 IPictureDisp *picdisp;
415 HRESULT hr;
416 VARIANTARG vararg;
417 DISPPARAMS dispparams;
418 VARIANT varresult;
419 IStream *stream;
420 HGLOBAL hglob;
421 void *data;
422
423 hglob = GlobalAlloc (0, sizeof(gifimage));
424 data = GlobalLock(hglob);
425 memcpy(data, gifimage, sizeof(gifimage));
426 GlobalUnlock(hglob);
427
428 hr = CreateStreamOnHGlobal (hglob, FALSE, &stream);
429 ok_ole_success(hr, "CreateStreamOnHGlobal");
430
431 hr = pOleLoadPicture(stream, sizeof(gifimage), TRUE, &IID_IPictureDisp, (void **)&picdisp);
432 IStream_Release(stream);
433 GlobalFree(hglob);
434 ok_ole_success(hr, "OleLoadPicture");
435
436 V_VT(&vararg) = VT_BOOL;
437 V_BOOL(&vararg) = VARIANT_FALSE;
438 dispparams.cNamedArgs = 0;
439 dispparams.rgdispidNamedArgs = NULL;
440 dispparams.cArgs = 1;
441 dispparams.rgvarg = &vararg;
442 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IPictureDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
443 ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
444 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IUnknown, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
445 ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
446
447 dispparams.cArgs = 0;
448 dispparams.rgvarg = NULL;
449 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
450 ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
451
452 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, NULL, NULL, NULL, NULL);
453 ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
454
455 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, NULL, NULL, NULL);
456 ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
457
458 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
459 ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
460
461 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
462 ok_ole_success(hr, "IPictureDisp_Invoke");
463 ok(V_VT(&varresult) == VT_I4, "V_VT(&varresult) should have been VT_UINT instead of %d\n", V_VT(&varresult));
464
465 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
466 ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
467
468 hr = IPictureDisp_Invoke(picdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
469 ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
470
471 dispparams.cArgs = 1;
472 dispparams.rgvarg = &vararg;
473 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
474 ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT 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 IPictureDisp_Release(picdisp);
482 }
483
484 static void test_OleCreatePictureIndirect(void)
485 {
486 OLE_HANDLE handle;
487 IPicture *pict;
488 HRESULT hr;
489 short type;
490
491 if(!pOleCreatePictureIndirect)
492 {
493 win_skip("Skipping OleCreatePictureIndirect tests\n");
494 return;
495 }
496
497 if (0)
498 {
499 /* crashes on native */
500 pOleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, NULL);
501 }
502
503 hr = pOleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
504 ok(hr == S_OK, "hr %08x\n", hr);
505
506 type = PICTYPE_NONE;
507 hr = IPicture_get_Type(pict, &type);
508 ok(hr == S_OK, "hr %08x\n", hr);
509 ok(type == PICTYPE_UNINITIALIZED, "type %d\n", type);
510
511 handle = 0xdeadbeef;
512 hr = IPicture_get_Handle(pict, &handle);
513 ok(hr == S_OK, "hr %08x\n", hr);
514 ok(handle == 0, "handle %08x\n", handle);
515
516 IPicture_Release(pict);
517 }
518
519 static void test_apm(void)
520 {
521 OLE_HANDLE handle;
522 LPSTREAM stream;
523 IPicture *pict;
524 HGLOBAL hglob;
525 LPBYTE *data;
526 LONG cxy;
527 BOOL keep;
528 short type;
529
530 hglob = GlobalAlloc (0, sizeof(apmdata));
531 data = GlobalLock(hglob);
532 memcpy(data, apmdata, sizeof(apmdata));
533
534 ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
535 ole_check(pOleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
536
537 ole_check(IPicture_get_Handle(pict, &handle));
538 ok(handle != 0, "handle is null\n");
539
540 ole_check(IPicture_get_Type(pict, &type));
541 expect_eq(type, PICTYPE_METAFILE, short, "%d");
542
543 ole_check(IPicture_get_Height(pict, &cxy));
544 expect_eq(cxy, 1667, LONG, "%d");
545
546 ole_check(IPicture_get_Width(pict, &cxy));
547 expect_eq(cxy, 1323, LONG, "%d");
548
549 ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
550 todo_wine expect_eq(keep, FALSE, LONG, "%d");
551
552 ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
553 IPicture_Release(pict);
554 IStream_Release(stream);
555 }
556
557 static void test_metafile(void)
558 {
559 LPSTREAM stream;
560 IPicture *pict;
561 HGLOBAL hglob;
562 LPBYTE *data;
563
564 hglob = GlobalAlloc (0, sizeof(metafile));
565 data = GlobalLock(hglob);
566 memcpy(data, metafile, sizeof(metafile));
567
568 ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
569 /* Windows does not load simple metafiles */
570 ole_expect(pOleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
571
572 IStream_Release(stream);
573 }
574
575 static void test_enhmetafile(void)
576 {
577 OLE_HANDLE handle;
578 LPSTREAM stream;
579 IPicture *pict;
580 HGLOBAL hglob;
581 LPBYTE *data;
582 LONG cxy;
583 BOOL keep;
584 short type;
585
586 hglob = GlobalAlloc (0, sizeof(enhmetafile));
587 data = GlobalLock(hglob);
588 memcpy(data, enhmetafile, sizeof(enhmetafile));
589
590 ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
591 ole_check(pOleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
592
593 ole_check(IPicture_get_Handle(pict, &handle));
594 ok(handle != 0, "handle is null\n");
595
596 ole_check(IPicture_get_Type(pict, &type));
597 expect_eq(type, PICTYPE_ENHMETAFILE, short, "%d");
598
599 ole_check(IPicture_get_Height(pict, &cxy));
600 expect_eq(cxy, -23, LONG, "%d");
601
602 ole_check(IPicture_get_Width(pict, &cxy));
603 expect_eq(cxy, -25, LONG, "%d");
604
605 ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
606 todo_wine expect_eq(keep, FALSE, LONG, "%d");
607
608 IPicture_Release(pict);
609 IStream_Release(stream);
610 }
611
612 static void test_Render(void)
613 {
614 IPicture *pic;
615 HRESULT hres;
616 short type;
617 PICTDESC desc;
618 OLE_XSIZE_HIMETRIC pWidth;
619 OLE_YSIZE_HIMETRIC pHeight;
620 COLORREF result, expected;
621 HDC hdc = GetDC(0);
622
623 /* test IPicture::Render return code on uninitialized picture */
624 OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
625 hres = IPicture_get_Type(pic, &type);
626 ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
627 ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
628 /* zero dimensions */
629 hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
630 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
631 hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
632 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
633 hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
634 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
635 hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
636 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
637 hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
638 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
639 hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
640 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
641 hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
642 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
643 /* nonzero dimensions, PICTYPE_UNINITIALIZED */
644 hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL);
645 ole_expect(hres, S_OK);
646 IPicture_Release(pic);
647
648 desc.cbSizeofstruct = sizeof(PICTDESC);
649 desc.picType = PICTYPE_ICON;
650 desc.u.icon.hicon = LoadIcon(NULL, IDI_APPLICATION);
651 if(!desc.u.icon.hicon){
652 win_skip("LoadIcon failed. Skipping...\n");
653 ReleaseDC(NULL, hdc);
654 return;
655 }
656
657 OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (VOID**)&pic);
658 /* zero dimensions, PICTYPE_ICON */
659 hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
660 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
661 hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
662 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
663 hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
664 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
665 hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
666 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
667 hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
668 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
669 hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
670 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
671 hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
672 ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
673
674 /* Check if target size and position is respected */
675 IPicture_get_Width(pic, &pWidth);
676 IPicture_get_Height(pic, &pHeight);
677
678 SetPixelV(hdc, 0, 0, 0x00223344);
679 SetPixelV(hdc, 5, 5, 0x00223344);
680 SetPixelV(hdc, 10, 10, 0x00223344);
681 expected = GetPixel(hdc, 0, 0);
682
683 hres = IPicture_Render(pic, hdc, 1, 1, 9, 9, 0, 0, pWidth, -pHeight, NULL);
684 ole_expect(hres, S_OK);
685
686 if(hres != S_OK) {
687 IPicture_Release(pic);
688 ReleaseDC(NULL, hdc);
689 return;
690 }
691
692 /* Evaluate the rendered Icon */
693 result = GetPixel(hdc, 0, 0);
694 ok(result == expected,
695 "Color at 0,0 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
696 result = GetPixel(hdc, 5, 5);
697 ok(result != expected ||
698 broken(result == expected), /* WinNT 4.0 and older may claim they drew */
699 /* the icon, even if they didn't. */
700 "Color at 5,5 should have changed, but still was 0x%06X\n", expected);
701 result = GetPixel(hdc, 10, 10);
702 ok(result == expected,
703 "Color at 10,10 should be unchanged 0x%06X, but was 0x%06X\n", expected, result);
704
705 IPicture_Release(pic);
706 ReleaseDC(NULL, hdc);
707 }
708
709 static void test_get_Attributes(void)
710 {
711 IPicture *pic;
712 HRESULT hres;
713 short type;
714 DWORD attr;
715
716 OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
717 hres = IPicture_get_Type(pic, &type);
718 ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
719 ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
720
721 hres = IPicture_get_Attributes(pic, NULL);
722 ole_expect(hres, E_POINTER);
723
724 attr = 0xdeadbeef;
725 hres = IPicture_get_Attributes(pic, &attr);
726 ole_expect(hres, S_OK);
727 ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %d\n", attr);
728
729 IPicture_Release(pic);
730 }
731
732 static void test_get_Handle(void)
733 {
734 IPicture *pic;
735 HRESULT hres;
736
737 OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
738
739 hres = IPicture_get_Handle(pic, NULL);
740 ole_expect(hres, E_POINTER);
741
742 IPicture_Release(pic);
743 }
744
745 static void test_get_Type(void)
746 {
747 IPicture *pic;
748 HRESULT hres;
749
750 OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (VOID**)&pic);
751
752 hres = IPicture_get_Type(pic, NULL);
753 ole_expect(hres, E_POINTER);
754
755 IPicture_Release(pic);
756 }
757
758 static void test_OleLoadPicturePath(void)
759 {
760 static WCHAR emptyW[] = {0};
761
762 IPicture *pic;
763 HRESULT hres;
764 int i;
765 char temp_path[MAX_PATH];
766 char temp_file[MAX_PATH];
767 WCHAR temp_fileW[MAX_PATH + 5] = {'f','i','l','e',':','/','/','/'};
768 HANDLE file;
769 DWORD size;
770 WCHAR *ptr;
771
772 const struct
773 {
774 LPOLESTR szURLorPath;
775 REFIID riid;
776 IPicture **pic;
777 } invalid_parameters[] =
778 {
779 {NULL, NULL, NULL},
780 {NULL, NULL, &pic},
781 {NULL, &IID_IPicture, NULL},
782 {NULL, &IID_IPicture, &pic},
783 {emptyW, NULL, NULL},
784 {emptyW, &IID_IPicture, NULL},
785 };
786
787 for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
788 {
789 pic = (IPicture *)0xdeadbeef;
790 hres = OleLoadPicturePath(invalid_parameters[i].szURLorPath, NULL, 0, 0,
791 invalid_parameters[i].riid,
792 (void **)invalid_parameters[i].pic);
793 ok(hres == E_INVALIDARG,
794 "[%d] Expected OleLoadPicturePath to return E_INVALIDARG, got 0x%08x\n", i, hres);
795 ok(pic == (IPicture *)0xdeadbeef,
796 "[%d] Expected output pointer to be 0xdeadbeef, got %p\n", i, pic);
797 }
798
799 pic = (IPicture *)0xdeadbeef;
800 hres = OleLoadPicturePath(emptyW, NULL, 0, 0, NULL, (void **)&pic);
801 todo_wine
802 ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
803 broken(hres == E_UNEXPECTED) || /* NT4 */
804 broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
805 "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
806 ok(pic == NULL,
807 "Expected the output interface pointer to be NULL, got %p\n", pic);
808
809 pic = (IPicture *)0xdeadbeef;
810 hres = OleLoadPicturePath(emptyW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
811 todo_wine
812 ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
813 broken(hres == E_UNEXPECTED) || /* NT4 */
814 broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
815 "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
816 ok(pic == NULL,
817 "Expected the output interface pointer to be NULL, got %p\n", pic);
818
819 /* Create a local temporary image file for testing. */
820 GetTempPathA(sizeof(temp_path), temp_path);
821 GetTempFileNameA(temp_path, "bmp", 0, temp_file);
822 file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
823 FILE_ATTRIBUTE_NORMAL, NULL);
824 WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
825 CloseHandle(file);
826
827 MultiByteToWideChar(CP_ACP, 0, temp_file, -1, temp_fileW + 8, sizeof(temp_fileW)/sizeof(WCHAR) - 8);
828
829 /* Try a normal DOS path. */
830 hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
831 ok(hres == S_OK ||
832 broken(hres == E_UNEXPECTED), /* NT4 */
833 "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
834 if (pic)
835 IPicture_Release(pic);
836
837 /* Try a DOS path with tacked on "file:". */
838 hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
839 ok(hres == S_OK ||
840 broken(hres == E_UNEXPECTED), /* NT4 */
841 "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
842 if (pic)
843 IPicture_Release(pic);
844
845 DeleteFileA(temp_file);
846
847 /* Try with a nonexistent file. */
848 hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
849 ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
850 broken(hres == E_UNEXPECTED) || /* NT4 */
851 broken(hres == E_FAIL), /*Win2k */
852 "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
853
854 hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
855 ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
856 broken(hres == E_UNEXPECTED) || /* NT4 */
857 broken(hres == E_FAIL), /* Win2k */
858 "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
859
860 file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
861 FILE_ATTRIBUTE_NORMAL, NULL);
862 WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
863 CloseHandle(file);
864
865 /* Try a "file:" URL with slash separators. */
866 ptr = temp_fileW + 8;
867 while (*ptr)
868 {
869 if (*ptr == '\\')
870 *ptr = '/';
871 ptr++;
872 }
873
874 hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
875 ok(hres == S_OK ||
876 broken(hres == E_UNEXPECTED), /* NT4 */
877 "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
878 if (pic)
879 IPicture_Release(pic);
880
881 DeleteFileA(temp_file);
882
883 /* Try with a nonexistent file. */
884 hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
885 ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
886 broken(hres == E_UNEXPECTED) || /* NT4 */
887 broken(hres == E_FAIL), /* Win2k */
888 "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
889 }
890
891 static void test_himetric(void)
892 {
893 static const BYTE bmp_bits[1024];
894 OLE_XSIZE_HIMETRIC cx;
895 OLE_YSIZE_HIMETRIC cy;
896 IPicture *pic;
897 PICTDESC desc;
898 HBITMAP bmp;
899 HRESULT hr;
900 HICON icon;
901 HDC hdc;
902 INT d;
903
904 if (!pOleCreatePictureIndirect)
905 {
906 win_skip("OleCreatePictureIndirect not available\n");
907 return;
908 }
909
910 desc.cbSizeofstruct = sizeof(desc);
911 desc.picType = PICTYPE_BITMAP;
912 desc.u.bmp.hpal = NULL;
913
914 hdc = CreateCompatibleDC(0);
915
916 bmp = CreateBitmap(1.9 * GetDeviceCaps(hdc, LOGPIXELSX),
917 1.9 * GetDeviceCaps(hdc, LOGPIXELSY), 1, 1, NULL);
918
919 desc.u.bmp.hbitmap = bmp;
920
921 /* size in himetric units reported rounded up to next integer value */
922 hr = pOleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
923 ok(hr == S_OK, "got 0x%08x\n", hr);
924
925 cx = 0;
926 d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSX)), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
927 hr = IPicture_get_Width(pic, &cx);
928 ok(hr == S_OK, "got 0x%08x\n", hr);
929 ok(cx == d, "got %d, expected %d\n", cx, d);
930
931 cy = 0;
932 d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSY)), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
933 hr = IPicture_get_Height(pic, &cy);
934 ok(hr == S_OK, "got 0x%08x\n", hr);
935 ok(cy == d, "got %d, expected %d\n", cy, d);
936
937 DeleteObject(bmp);
938 IPicture_Release(pic);
939
940 /* same thing with icon */
941 icon = CreateIcon(NULL, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
942 1, 1, bmp_bits, bmp_bits);
943 ok(icon != NULL, "failed to create icon\n");
944
945 desc.picType = PICTYPE_ICON;
946 desc.u.icon.hicon = icon;
947
948 hr = pOleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
949 ok(hr == S_OK, "got 0x%08x\n", hr);
950
951 cx = 0;
952 d = MulDiv(GetSystemMetrics(SM_CXICON), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
953 hr = IPicture_get_Width(pic, &cx);
954 ok(hr == S_OK, "got 0x%08x\n", hr);
955 ok(cx == d, "got %d, expected %d\n", cx, d);
956
957 cy = 0;
958 d = MulDiv(GetSystemMetrics(SM_CYICON), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
959 hr = IPicture_get_Height(pic, &cy);
960 ok(hr == S_OK, "got 0x%08x\n", hr);
961 ok(cy == d, "got %d, expected %d\n", cy, d);
962
963 IPicture_Release(pic);
964 DestroyIcon(icon);
965
966 DeleteDC(hdc);
967 }
968
969 START_TEST(olepicture)
970 {
971 hOleaut32 = GetModuleHandleA("oleaut32.dll");
972 pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
973 pOleLoadPictureEx = (void*)GetProcAddress(hOleaut32, "OleLoadPictureEx");
974 pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect");
975 if (!pOleLoadPicture)
976 {
977 win_skip("OleLoadPicture is not available\n");
978 return;
979 }
980
981 /* Test regular 1x1 pixel images of gif, jpg, bmp type */
982 test_pic(gifimage, sizeof(gifimage));
983 test_pic(jpgimage, sizeof(jpgimage));
984 test_pic(bmpimage, sizeof(bmpimage));
985 test_pic(gif4pixel, sizeof(gif4pixel));
986 /* FIXME: No PNG support in Windows... */
987 if (0) test_pic(pngimage, sizeof(pngimage));
988 test_empty_image();
989 test_empty_image_2();
990 if (pOleLoadPictureEx)
991 {
992 test_apm();
993 test_metafile();
994 test_enhmetafile();
995 }
996 else
997 win_skip("OleLoadPictureEx is not available\n");
998 test_Invoke();
999 test_OleCreatePictureIndirect();
1000 test_Render();
1001 test_get_Attributes();
1002 test_get_Handle();
1003 test_get_Type();
1004 test_OleLoadPicturePath();
1005 test_himetric();
1006 }
1007
1008
1009 /* Helper functions only ... */
1010
1011
1012 static inline NoStatStreamImpl *impl_from_IStream(IStream *iface)
1013 {
1014 return CONTAINING_RECORD(iface, NoStatStreamImpl, IStream_iface);
1015 }
1016
1017 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
1018 {
1019 GlobalFree(This->supportHandle);
1020 This->supportHandle=0;
1021 HeapFree(GetProcessHeap(), 0, This);
1022 }
1023
1024 static ULONG WINAPI NoStatStreamImpl_AddRef(
1025 IStream* iface)
1026 {
1027 NoStatStreamImpl* const This = impl_from_IStream(iface);
1028 return InterlockedIncrement(&This->ref);
1029 }
1030
1031 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
1032 IStream* iface,
1033 REFIID riid, /* [in] */
1034 void** ppvObject) /* [iid_is][out] */
1035 {
1036 NoStatStreamImpl* const This = impl_from_IStream(iface);
1037 if (ppvObject==0) return E_INVALIDARG;
1038 *ppvObject = 0;
1039 if (IsEqualIID(&IID_IUnknown, riid))
1040 {
1041 *ppvObject = This;
1042 }
1043 else if (IsEqualIID(&IID_IStream, riid))
1044 {
1045 *ppvObject = This;
1046 }
1047
1048 if ((*ppvObject)==0)
1049 return E_NOINTERFACE;
1050 NoStatStreamImpl_AddRef(iface);
1051 return S_OK;
1052 }
1053
1054 static ULONG WINAPI NoStatStreamImpl_Release(
1055 IStream* iface)
1056 {
1057 NoStatStreamImpl* const This = impl_from_IStream(iface);
1058 ULONG newRef = InterlockedDecrement(&This->ref);
1059 if (newRef==0)
1060 NoStatStreamImpl_Destroy(This);
1061 return newRef;
1062 }
1063
1064 static HRESULT WINAPI NoStatStreamImpl_Read(
1065 IStream* iface,
1066 void* pv, /* [length_is][size_is][out] */
1067 ULONG cb, /* [in] */
1068 ULONG* pcbRead) /* [out] */
1069 {
1070 NoStatStreamImpl* const This = impl_from_IStream(iface);
1071 void* supportBuffer;
1072 ULONG bytesReadBuffer;
1073 ULONG bytesToReadFromBuffer;
1074
1075 if (pcbRead==0)
1076 pcbRead = &bytesReadBuffer;
1077 bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
1078 supportBuffer = GlobalLock(This->supportHandle);
1079 memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
1080 This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
1081 *pcbRead = bytesToReadFromBuffer;
1082 GlobalUnlock(This->supportHandle);
1083 if(*pcbRead == cb)
1084 return S_OK;
1085 return S_FALSE;
1086 }
1087
1088 static HRESULT WINAPI NoStatStreamImpl_Write(
1089 IStream* iface,
1090 const void* pv, /* [size_is][in] */
1091 ULONG cb, /* [in] */
1092 ULONG* pcbWritten) /* [out] */
1093 {
1094 NoStatStreamImpl* const This = impl_from_IStream(iface);
1095 void* supportBuffer;
1096 ULARGE_INTEGER newSize;
1097 ULONG bytesWritten = 0;
1098
1099 if (pcbWritten == 0)
1100 pcbWritten = &bytesWritten;
1101 if (cb == 0)
1102 return S_OK;
1103 newSize.u.HighPart = 0;
1104 newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
1105 if (newSize.u.LowPart > This->streamSize.u.LowPart)
1106 IStream_SetSize(iface, newSize);
1107
1108 supportBuffer = GlobalLock(This->supportHandle);
1109 memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
1110 This->currentPosition.u.LowPart+=cb;
1111 *pcbWritten = cb;
1112 GlobalUnlock(This->supportHandle);
1113 return S_OK;
1114 }
1115
1116 static HRESULT WINAPI NoStatStreamImpl_Seek(
1117 IStream* iface,
1118 LARGE_INTEGER dlibMove, /* [in] */
1119 DWORD dwOrigin, /* [in] */
1120 ULARGE_INTEGER* plibNewPosition) /* [out] */
1121 {
1122 NoStatStreamImpl* const This = impl_from_IStream(iface);
1123 ULARGE_INTEGER newPosition;
1124 switch (dwOrigin)
1125 {
1126 case STREAM_SEEK_SET:
1127 newPosition.u.HighPart = 0;
1128 newPosition.u.LowPart = 0;
1129 break;
1130 case STREAM_SEEK_CUR:
1131 newPosition = This->currentPosition;
1132 break;
1133 case STREAM_SEEK_END:
1134 newPosition = This->streamSize;
1135 break;
1136 default:
1137 return STG_E_INVALIDFUNCTION;
1138 }
1139 if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
1140 return STG_E_INVALIDFUNCTION;
1141 newPosition.QuadPart += dlibMove.QuadPart;
1142 if (plibNewPosition) *plibNewPosition = newPosition;
1143 This->currentPosition = newPosition;
1144 return S_OK;
1145 }
1146
1147 static HRESULT WINAPI NoStatStreamImpl_SetSize(
1148 IStream* iface,
1149 ULARGE_INTEGER libNewSize) /* [in] */
1150 {
1151 NoStatStreamImpl* const This = impl_from_IStream(iface);
1152 HGLOBAL supportHandle;
1153 if (libNewSize.u.HighPart != 0)
1154 return STG_E_INVALIDFUNCTION;
1155 if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
1156 return S_OK;
1157 supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
1158 if (supportHandle == 0)
1159 return STG_E_MEDIUMFULL;
1160 This->supportHandle = supportHandle;
1161 This->streamSize.u.LowPart = libNewSize.u.LowPart;
1162 return S_OK;
1163 }
1164
1165 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
1166 IStream* iface,
1167 IStream* pstm, /* [unique][in] */
1168 ULARGE_INTEGER cb, /* [in] */
1169 ULARGE_INTEGER* pcbRead, /* [out] */
1170 ULARGE_INTEGER* pcbWritten) /* [out] */
1171 {
1172 HRESULT hr = S_OK;
1173 BYTE tmpBuffer[128];
1174 ULONG bytesRead, bytesWritten, copySize;
1175 ULARGE_INTEGER totalBytesRead;
1176 ULARGE_INTEGER totalBytesWritten;
1177
1178 if ( pstm == 0 )
1179 return STG_E_INVALIDPOINTER;
1180 totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
1181 totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
1182
1183 while ( cb.u.LowPart > 0 )
1184 {
1185 if ( cb.u.LowPart >= 128 )
1186 copySize = 128;
1187 else
1188 copySize = cb.u.LowPart;
1189 IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1190 totalBytesRead.u.LowPart += bytesRead;
1191 IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1192 totalBytesWritten.u.LowPart += bytesWritten;
1193 if (bytesRead != bytesWritten)
1194 {
1195 hr = STG_E_MEDIUMFULL;
1196 break;
1197 }
1198 if (bytesRead!=copySize)
1199 cb.u.LowPart = 0;
1200 else
1201 cb.u.LowPart -= bytesRead;
1202 }
1203 if (pcbRead)
1204 {
1205 pcbRead->u.LowPart = totalBytesRead.u.LowPart;
1206 pcbRead->u.HighPart = totalBytesRead.u.HighPart;
1207 }
1208
1209 if (pcbWritten)
1210 {
1211 pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
1212 pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
1213 }
1214 return hr;
1215 }
1216
1217 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
1218 {
1219 return S_OK;
1220 }
1221 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
1222
1223 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
1224 IStream* iface,
1225 ULARGE_INTEGER libOffset, /* [in] */
1226 ULARGE_INTEGER cb, /* [in] */
1227 DWORD dwLockType) /* [in] */
1228 {
1229 return S_OK;
1230 }
1231
1232 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
1233 IStream* iface,
1234 ULARGE_INTEGER libOffset, /* [in] */
1235 ULARGE_INTEGER cb, /* [in] */
1236 DWORD dwLockType) /* [in] */
1237 {
1238 return S_OK;
1239 }
1240
1241 static HRESULT WINAPI NoStatStreamImpl_Stat(
1242 IStream* iface,
1243 STATSTG* pstatstg, /* [out] */
1244 DWORD grfStatFlag) /* [in] */
1245 {
1246 return E_NOTIMPL;
1247 }
1248
1249 static HRESULT WINAPI NoStatStreamImpl_Clone(
1250 IStream* iface,
1251 IStream** ppstm) /* [out] */
1252 {
1253 return E_NOTIMPL;
1254 }
1255 static const IStreamVtbl NoStatStreamImpl_Vtbl;
1256
1257 /*
1258 Build an object that implements IStream, without IStream_Stat capabilities.
1259 Receives a memory handle with data buffer. If memory handle is non-null,
1260 it is assumed to be unlocked, otherwise an internal memory handle is allocated.
1261 In any case the object takes ownership of memory handle and will free it on
1262 object release.
1263 */
1264 static IStream* NoStatStream_Construct(HGLOBAL hGlobal)
1265 {
1266 NoStatStreamImpl* newStream;
1267
1268 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
1269 if (newStream!=0)
1270 {
1271 newStream->IStream_iface.lpVtbl = &NoStatStreamImpl_Vtbl;
1272 newStream->ref = 1;
1273 newStream->supportHandle = hGlobal;
1274
1275 if (!newStream->supportHandle)
1276 newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
1277 GMEM_SHARE, 0);
1278 newStream->currentPosition.u.HighPart = 0;
1279 newStream->currentPosition.u.LowPart = 0;
1280 newStream->streamSize.u.HighPart = 0;
1281 newStream->streamSize.u.LowPart = GlobalSize(newStream->supportHandle);
1282 }
1283 return &newStream->IStream_iface;
1284 }
1285
1286
1287 static const IStreamVtbl NoStatStreamImpl_Vtbl =
1288 {
1289 NoStatStreamImpl_QueryInterface,
1290 NoStatStreamImpl_AddRef,
1291 NoStatStreamImpl_Release,
1292 NoStatStreamImpl_Read,
1293 NoStatStreamImpl_Write,
1294 NoStatStreamImpl_Seek,
1295 NoStatStreamImpl_SetSize,
1296 NoStatStreamImpl_CopyTo,
1297 NoStatStreamImpl_Commit,
1298 NoStatStreamImpl_Revert,
1299 NoStatStreamImpl_LockRegion,
1300 NoStatStreamImpl_UnlockRegion,
1301 NoStatStreamImpl_Stat,
1302 NoStatStreamImpl_Clone
1303 };
1304
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.