[KMTestSuite]
[reactos.git] / winetests / oleaut32 / olepicture.c
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 NONAMELESSUNION
29
30 #include "wine/test.h"
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winuser.h>
34 #include <wingdi.h>
35 #include <winnls.h>
36 #include <winerror.h>
37 #include <winnt.h>
38
39 #include <urlmon.h>
40 #include <wtypes.h>
41 #include <olectl.h>
42 #include <objidl.h>
43
44 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
45
46 #define ole_expect(expr, expect) { \
47 HRESULT r = expr; \
48 ok(r == (expect), #expr " returned %x, expected %s (%x)\n", r, #expect, expect); \
49 }
50
51 #define ole_check(expr) ole_expect(expr, S_OK);
52
53 static HMODULE hOleaut32;
54
55 static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);
56 static HRESULT (WINAPI *pOleCreatePictureIndirect)(PICTDESC*,REFIID,BOOL,LPVOID*);
57
58 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
59
60 /* 1x1 pixel gif */
61 static const unsigned char gifimage[35] = {
62 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
63 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
64 0x01,0x00,0x3b
65 };
66
67 /* 1x1 pixel jpg */
68 static const unsigned char jpgimage[285] = {
69 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
70 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
71 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
72 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
73 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
74 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
75 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
76 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
77 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
78 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
79 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
80 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
81 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
82 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
83 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
84 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
85 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
86 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
87 };
88
89 /* 1x1 pixel png */
90 static const unsigned char pngimage[285] = {
91 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
92 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
93 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
94 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
95 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
96 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
97 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
98 };
99
100 /* 1x1 pixel bmp */
101 static const unsigned char bmpimage[66] = {
102 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
103 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
104 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
105 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
106 0x00,0x00
107 };
108
109 /* 2x2 pixel gif */
110 static const unsigned char gif4pixel[42] = {
111 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
112 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
113 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
114 };
115
116 /* APM with an empty metafile with some padding zeros - looks like under Window the
117 * metafile data should be at least 20 bytes */
118 static const unsigned char apmdata[] = {
119 0xd7,0xcd,0xc6,0x9a, 0x00,0x00,0x00,0x00, 0x00,0x00,0xee,0x02, 0xb1,0x03,0xa0,0x05,
120 0x00,0x00,0x00,0x00, 0xee,0x53,0x01,0x00, 0x09,0x00,0x00,0x03, 0x13,0x00,0x00,0x00,
121 0x01,0x00,0x05,0x00, 0x00,0x00,0x00,0x00, 0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
122 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
123 };
124
125 /* MF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
126 static const unsigned char metafile[] = {
127 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
128 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
130 0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
131 0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
132 0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
133 0x00, 0x00
134 };
135
136 /* EMF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
137 static const unsigned char enhmetafile[] = {
138 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
143 0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
144 0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
145 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
148 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
151 0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
152 0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
153 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
155 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
157 0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
158 0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
161 0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
162 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
163 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
164 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
165 0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
166 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
167 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
168 0x14, 0x00, 0x00, 0x00
169 };
170
171
172 struct NoStatStreamImpl
173 {
174 const IStreamVtbl *lpVtbl;
175 LONG ref;
176
177 HGLOBAL supportHandle;
178 ULARGE_INTEGER streamSize;
179 ULARGE_INTEGER currentPosition;
180 };
181 typedef struct NoStatStreamImpl NoStatStreamImpl;
182 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal);
183
184 static void
185 test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
186 {
187 IPicture* pic = NULL;
188 HRESULT hres;
189 LPVOID pvObj = NULL;
190 OLE_HANDLE handle, hPal;
191 OLE_XSIZE_HIMETRIC width;
192 OLE_YSIZE_HIMETRIC height;
193 short type;
194 DWORD attr;
195 ULONG res;
196
197 pvObj = NULL;
198 hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
199 pic = pvObj;
200
201 ok(hres == S_OK,"OLP (NULL,..) does not return 0, but 0x%08x\n",hres);
202 ok(pic != NULL,"OLP (NULL,..) returns NULL, instead of !NULL\n");
203 if (pic == NULL)
204 return;
205
206 pvObj = NULL;
207 hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);
208
209 ok(hres == S_OK,"IPicture_QI does not return S_OK, but 0x%08x\n", hres);
210 ok(pvObj != NULL,"IPicture_QI does return NULL, instead of a ptr\n");
211
212 IPicture_Release ((IPicture*)pvObj);
213
214 handle = 0;
215 hres = IPicture_get_Handle (pic, &handle);
216 ok(hres == S_OK,"IPicture_get_Handle does not return S_OK, but 0x%08x\n", hres);
217 ok(handle != 0, "IPicture_get_Handle returns a NULL handle, but it should be non NULL\n");
218
219 if (handle)
220 {
221 BITMAP bmp;
222 GetObject((HGDIOBJ)handle, sizeof(BITMAP), &bmp);
223 todo_wine ok(bmp.bmBits != 0, "not a dib\n");
224 }
225
226 width = 0;
227 hres = IPicture_get_Width (pic, &width);
228 ok(hres == S_OK,"IPicture_get_Width does not return S_OK, but 0x%08x\n", hres);
229 ok(width != 0, "IPicture_get_Width returns 0, but it should not be 0.\n");
230
231 height = 0;
232 hres = IPicture_get_Height (pic, &height);
233 ok(hres == S_OK,"IPicture_get_Height does not return S_OK, but 0x%08x\n", hres);
234 ok(height != 0, "IPicture_get_Height returns 0, but it should not be 0.\n");
235
236 type = 0;
237 hres = IPicture_get_Type (pic, &type);
238 ok(hres == S_OK,"IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
239 ok(type == PICTYPE_BITMAP, "IPicture_get_Type returns %d, but it should be PICTYPE_BITMAP(%d).\n", type, PICTYPE_BITMAP);
240
241 attr = 0;
242 hres = IPicture_get_Attributes (pic, &attr);
243 ok(hres == S_OK,"IPicture_get_Attributes does not return S_OK, but 0x%08x\n", hres);
244 ok(attr == 0, "IPicture_get_Attributes returns %d, but it should be 0.\n", attr);
245
246 hPal = 0;
247 hres = IPicture_get_hPal (pic, &hPal);
248 ok(hres == S_OK,"IPicture_get_hPal does not return S_OK, but 0x%08x\n", hres);
249 /* a single pixel b/w image has no palette */
250 ok(hPal == 0, "IPicture_get_hPal returns %d, but it should be 0.\n", hPal);
251
252 res = IPicture_Release (pic);
253 ok (res == 0, "refcount after release is %d, but should be 0?\n", res);
254 }
255
256 static void
257 test_pic(const unsigned char *imgdata, unsigned int imgsize)
258 {
259 LPSTREAM stream;
260 HGLOBAL hglob;
261 LPBYTE data;
262 HRESULT hres;
263 LARGE_INTEGER seekto;
264 ULARGE_INTEGER newpos1;
265 DWORD * header;
266 unsigned int i,j;
267
268 /* Let the fun begin */
269 hglob = GlobalAlloc (0, imgsize);
270 data = GlobalLock (hglob);
271 memcpy(data, imgdata, imgsize);
272 GlobalUnlock(hglob); data = NULL;
273
274 hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
275 ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
276
277 memset(&seekto,0,sizeof(seekto));
278 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
279 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
280 test_pic_with_stream(stream, imgsize);
281
282 IStream_Release(stream);
283
284 /* again with Non Statable and Non Seekable stream */
285 stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
286 hglob = 0; /* Non-statable impl always deletes on release */
287 test_pic_with_stream(stream, 0);
288
289 IStream_Release(stream);
290 for (i = 1; i <= 8; i++) {
291 /* more fun!!! */
292 hglob = GlobalAlloc (0, imgsize + i * (2 * sizeof(DWORD)));
293 data = GlobalLock (hglob);
294 header = (DWORD *)data;
295
296 /* multiple copies of header */
297 memcpy(data,"lt\0\0",4);
298 header[1] = imgsize;
299 for (j = 2; j <= i; j++) {
300 memcpy(&(header[2 * (j - 1)]), header, 2 * sizeof(DWORD));
301 }
302 memcpy(data + i * (2 * sizeof(DWORD)), imgdata, imgsize);
303 GlobalUnlock(hglob); data = NULL;
304
305 hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
306 ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
307
308 memset(&seekto,0,sizeof(seekto));
309 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
310 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
311 test_pic_with_stream(stream, imgsize);
312
313 IStream_Release(stream);
314
315 /* again with Non Statable and Non Seekable stream */
316 stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
317 hglob = 0; /* Non-statable impl always deletes on release */
318 test_pic_with_stream(stream, 0);
319
320 IStream_Release(stream);
321 }
322 }
323
324 static void test_empty_image(void) {
325 LPBYTE data;
326 LPSTREAM stream;
327 IPicture* pic = NULL;
328 HRESULT hres;
329 LPVOID pvObj = NULL;
330 HGLOBAL hglob;
331 OLE_HANDLE handle;
332 ULARGE_INTEGER newpos1;
333 LARGE_INTEGER seekto;
334 short type;
335 DWORD attr;
336
337 /* Empty image. Happens occasionally in VB programs. */
338 hglob = GlobalAlloc (0, 8);
339 data = GlobalLock (hglob);
340 memcpy(data,"lt\0\0",4);
341 ((DWORD*)data)[1] = 0;
342 hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
343 ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
344
345 memset(&seekto,0,sizeof(seekto));
346 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
347 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
348
349 pvObj = NULL;
350 hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
351 pic = pvObj;
352 ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
353 ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
354
355 hres = IPicture_get_Type (pic, &type);
356 ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
357 ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
358
359 attr = 0xdeadbeef;
360 hres = IPicture_get_Attributes (pic, &attr);
361 ok (hres == S_OK,"empty picture get attributes failed with hres 0x%08x\n", hres);
362 ok (attr == 0,"attr is %d, but should be 0\n", attr);
363
364 hres = IPicture_get_Handle (pic, &handle);
365 ok (hres == S_OK,"empty picture get handle failed with hres 0x%08x\n", hres);
366 ok (handle == 0, "empty picture get handle did not return 0, but 0x%08x\n", handle);
367 IPicture_Release (pic);
368 IStream_Release (stream);
369 }
370
371 static void test_empty_image_2(void) {
372 LPBYTE data;
373 LPSTREAM stream;
374 IPicture* pic = NULL;
375 HRESULT hres;
376 LPVOID pvObj = NULL;
377 HGLOBAL hglob;
378 ULARGE_INTEGER newpos1;
379 LARGE_INTEGER seekto;
380 short type;
381
382 /* Empty image at random stream position. */
383 hglob = GlobalAlloc (0, 200);
384 data = GlobalLock (hglob);
385 data += 42;
386 memcpy(data,"lt\0\0",4);
387 ((DWORD*)data)[1] = 0;
388 hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
389 ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
390
391 memset(&seekto,0,sizeof(seekto));
392 seekto.u.LowPart = 42;
393 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
394 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
395
396 pvObj = NULL;
397 hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
398 pic = pvObj;
399 ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
400 ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
401
402 hres = IPicture_get_Type (pic, &type);
403 ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
404 ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
405
406 IPicture_Release (pic);
407 IStream_Release (stream);
408 }
409
410 static void test_Invoke(void)
411 {
412 IPictureDisp *picdisp;
413 HRESULT hr;
414 VARIANTARG vararg;
415 DISPPARAMS dispparams;
416 VARIANT varresult;
417 IStream *stream;
418 HGLOBAL hglob;
419 void *data;
420
421 hglob = GlobalAlloc (0, sizeof(gifimage));
422 data = GlobalLock(hglob);
423 memcpy(data, gifimage, sizeof(gifimage));
424 GlobalUnlock(hglob);
425
426 hr = CreateStreamOnHGlobal (hglob, FALSE, &stream);
427 ok_ole_success(hr, "CreateStreamOnHGlobal");
428
429 hr = pOleLoadPicture(stream, sizeof(gifimage), TRUE, &IID_IPictureDisp, (void **)&picdisp);
430 IStream_Release(stream);
431 GlobalFree(hglob);
432 ok_ole_success(hr, "OleLoadPicture");
433
434 V_VT(&vararg) = VT_BOOL;
435 V_BOOL(&vararg) = VARIANT_FALSE;
436 dispparams.cNamedArgs = 0;
437 dispparams.rgdispidNamedArgs = NULL;
438 dispparams.cArgs = 1;
439 dispparams.rgvarg = &vararg;
440 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IPictureDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
441 ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
442 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IUnknown, 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
445 dispparams.cArgs = 0;
446 dispparams.rgvarg = NULL;
447 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
448 ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
449
450 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, NULL, NULL, NULL, NULL);
451 ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
452
453 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, NULL, NULL, NULL);
454 ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
455
456 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
457 ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
458
459 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
460 ok_ole_success(hr, "IPictureDisp_Invoke");
461 ok(V_VT(&varresult) == VT_I4, "V_VT(&varresult) should have been VT_UINT instead of %d\n", V_VT(&varresult));
462
463 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
464 ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
465
466 hr = IPictureDisp_Invoke(picdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
467 ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
468
469 dispparams.cArgs = 1;
470 dispparams.rgvarg = &vararg;
471 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
472 ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
473
474 dispparams.cArgs = 1;
475 dispparams.rgvarg = &vararg;
476 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
477 ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
478
479 IPictureDisp_Release(picdisp);
480 }
481
482 static void test_OleCreatePictureIndirect(void)
483 {
484 IPicture *pict;
485 HRESULT hr;
486 short type;
487 OLE_HANDLE handle;
488
489 if(!pOleCreatePictureIndirect)
490 {
491 win_skip("Skipping OleCreatePictureIndirect tests\n");
492 return;
493 }
494
495 hr = pOleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
496 ok(hr == S_OK, "hr %08x\n", hr);
497
498 hr = IPicture_get_Type(pict, &type);
499 ok(hr == S_OK, "hr %08x\n", hr);
500 ok(type == PICTYPE_UNINITIALIZED, "type %d\n", type);
501
502 hr = IPicture_get_Handle(pict, &handle);
503 ok(hr == S_OK, "hr %08x\n", hr);
504 ok(handle == 0, "handle %08x\n", handle);
505
506 IPicture_Release(pict);
507 }
508
509 static void test_apm(void)
510 {
511 OLE_HANDLE handle;
512 LPSTREAM stream;
513 IPicture *pict;
514 HGLOBAL hglob;
515 LPBYTE *data;
516 LONG cxy;
517 BOOL keep;
518 short type;
519
520 if(!winetest_interactive) {
521 skip("Bug 5000: oleaut_winetest:olepicture crashes with Page Fault.\n");
522 return;
523 }
524
525 hglob = GlobalAlloc (0, sizeof(apmdata));
526 data = GlobalLock(hglob);
527 memcpy(data, apmdata, sizeof(apmdata));
528
529 ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
530 ole_check(OleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
531
532 ole_check(IPicture_get_Handle(pict, &handle));
533 ok(handle != 0, "handle is null\n");
534
535 ole_check(IPicture_get_Type(pict, &type));
536 expect_eq(type, PICTYPE_METAFILE, short, "%d");
537
538 ole_check(IPicture_get_Height(pict, &cxy));
539 expect_eq(cxy, 1667, LONG, "%d");
540
541 ole_check(IPicture_get_Width(pict, &cxy));
542 expect_eq(cxy, 1323, LONG, "%d");
543
544 ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
545 todo_wine expect_eq(keep, FALSE, LONG, "%d");
546
547 ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
548 IPicture_Release(pict);
549 IStream_Release(stream);
550 }
551
552 static void test_metafile(void)
553 {
554 LPSTREAM stream;
555 IPicture *pict;
556 HGLOBAL hglob;
557 LPBYTE *data;
558
559 hglob = GlobalAlloc (0, sizeof(metafile));
560 data = GlobalLock(hglob);
561 memcpy(data, metafile, sizeof(metafile));
562
563 ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
564 /* Windows does not load simple metafiles */
565 ole_expect(OleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
566
567 IStream_Release(stream);
568 }
569
570 static void test_enhmetafile(void)
571 {
572 OLE_HANDLE handle;
573 LPSTREAM stream;
574 IPicture *pict;
575 HGLOBAL hglob;
576 LPBYTE *data;
577 LONG cxy;
578 BOOL keep;
579 short type;
580
581 if(!winetest_interactive) {
582 skip("Bug 5000: oleaut_winetest:olepicture crashes with Page Fault.\n");
583 return;
584 }
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(OleLoadPictureEx(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, 0x00F0F0F0);
679 SetPixelV(hdc, 5, 5, 0x00F0F0F0);
680 SetPixelV(hdc, 10, 10, 0x00F0F0F0);
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 hres == E_UNEXPECTED || /* NT4/Win95 */
804 hres == E_FAIL || /* Win95 OSR2 */
805 hres == E_OUTOFMEMORY, /* Win98/Win2k/Win2k3 */
806 "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
807 ok(pic == NULL,
808 "Expected the output interface pointer to be NULL, got %p\n", pic);
809
810 pic = (IPicture *)0xdeadbeef;
811 hres = OleLoadPicturePath(emptyW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
812 todo_wine
813 ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
814 hres == E_UNEXPECTED || /* NT4/Win95 */
815 hres == E_FAIL || /* Win95 OSR2 */
816 hres == E_OUTOFMEMORY, /* Win98/Win2k/Win2k3 */
817 "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
818 ok(pic == NULL,
819 "Expected the output interface pointer to be NULL, got %p\n", pic);
820
821 /* Create a local temporary image file for testing. */
822 GetTempPathA(sizeof(temp_path), temp_path);
823 GetTempFileNameA(temp_path, "bmp", 0, temp_file);
824 file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
825 FILE_ATTRIBUTE_NORMAL, NULL);
826 WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
827 CloseHandle(file);
828
829 MultiByteToWideChar(CP_ACP, 0, temp_file, -1, temp_fileW + 8, sizeof(temp_fileW)/sizeof(WCHAR) - 8);
830
831 /* Try a normal DOS path. */
832 hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
833 ok(hres == S_OK ||
834 broken(hres == E_UNEXPECTED), /* NT4/Win95 */
835 "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
836 if (pic)
837 IPicture_Release(pic);
838
839 /* Try a DOS path with tacked on "file:". */
840 hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
841 ok(hres == S_OK ||
842 broken(hres == E_UNEXPECTED), /* NT4/Win95 */
843 "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
844 if (pic)
845 IPicture_Release(pic);
846
847 DeleteFileA(temp_file);
848
849 /* Try with a nonexistent file. */
850 hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
851 ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
852 hres == E_UNEXPECTED || /* NT4/Win95 */
853 hres == E_FAIL, /* Win9x/Win2k */
854 "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
855
856 hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
857 ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
858 hres == E_UNEXPECTED || /* NT4/Win95 */
859 hres == E_FAIL, /* Win9x/Win2k */
860 "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
861
862 file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
863 FILE_ATTRIBUTE_NORMAL, NULL);
864 WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
865 CloseHandle(file);
866
867 /* Try a "file:" URL with slash separators. */
868 ptr = temp_fileW + 8;
869 while (*ptr)
870 {
871 if (*ptr == '\\')
872 *ptr = '/';
873 ptr++;
874 }
875
876 hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
877 ok(hres == S_OK ||
878 broken(hres == E_UNEXPECTED), /* NT4/Win95 */
879 "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
880 if (pic)
881 IPicture_Release(pic);
882
883 DeleteFileA(temp_file);
884
885 /* Try with a nonexistent file. */
886 hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
887 ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
888 hres == E_UNEXPECTED || /* NT4/Win95 */
889 hres == E_FAIL, /* Win9x/Win2k */
890 "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
891 }
892
893 START_TEST(olepicture)
894 {
895 hOleaut32 = GetModuleHandleA("oleaut32.dll");
896 pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
897 pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect");
898 if (!pOleLoadPicture)
899 {
900 win_skip("OleLoadPicture is not available\n");
901 return;
902 }
903
904 /* Test regular 1x1 pixel images of gif, jpg, bmp type */
905 test_pic(gifimage, sizeof(gifimage));
906 test_pic(jpgimage, sizeof(jpgimage));
907 test_pic(bmpimage, sizeof(bmpimage));
908 test_pic(gif4pixel, sizeof(gif4pixel));
909 /* FIXME: No PNG support in Windows... */
910 if (0) test_pic(pngimage, sizeof(pngimage));
911 test_empty_image();
912 test_empty_image_2();
913 test_apm();
914 test_metafile();
915 test_enhmetafile();
916
917 test_Invoke();
918 test_OleCreatePictureIndirect();
919 test_Render();
920 test_get_Attributes();
921 test_get_Handle();
922 test_get_Type();
923 test_OleLoadPicturePath();
924 }
925
926
927 /* Helper functions only ... */
928
929
930 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
931 {
932 GlobalFree(This->supportHandle);
933 This->supportHandle=0;
934 HeapFree(GetProcessHeap(), 0, This);
935 }
936
937 static ULONG WINAPI NoStatStreamImpl_AddRef(
938 IStream* iface)
939 {
940 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
941 return InterlockedIncrement(&This->ref);
942 }
943
944 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
945 IStream* iface,
946 REFIID riid, /* [in] */
947 void** ppvObject) /* [iid_is][out] */
948 {
949 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
950 if (ppvObject==0) return E_INVALIDARG;
951 *ppvObject = 0;
952 if (IsEqualIID(&IID_IUnknown, riid))
953 {
954 *ppvObject = This;
955 }
956 else if (IsEqualIID(&IID_IStream, riid))
957 {
958 *ppvObject = This;
959 }
960
961 if ((*ppvObject)==0)
962 return E_NOINTERFACE;
963 NoStatStreamImpl_AddRef(iface);
964 return S_OK;
965 }
966
967 static ULONG WINAPI NoStatStreamImpl_Release(
968 IStream* iface)
969 {
970 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
971 ULONG newRef = InterlockedDecrement(&This->ref);
972 if (newRef==0)
973 NoStatStreamImpl_Destroy(This);
974 return newRef;
975 }
976
977 static HRESULT WINAPI NoStatStreamImpl_Read(
978 IStream* iface,
979 void* pv, /* [length_is][size_is][out] */
980 ULONG cb, /* [in] */
981 ULONG* pcbRead) /* [out] */
982 {
983 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
984 void* supportBuffer;
985 ULONG bytesReadBuffer;
986 ULONG bytesToReadFromBuffer;
987
988 if (pcbRead==0)
989 pcbRead = &bytesReadBuffer;
990 bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
991 supportBuffer = GlobalLock(This->supportHandle);
992 memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
993 This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
994 *pcbRead = bytesToReadFromBuffer;
995 GlobalUnlock(This->supportHandle);
996 if(*pcbRead == cb)
997 return S_OK;
998 return S_FALSE;
999 }
1000
1001 static HRESULT WINAPI NoStatStreamImpl_Write(
1002 IStream* iface,
1003 const void* pv, /* [size_is][in] */
1004 ULONG cb, /* [in] */
1005 ULONG* pcbWritten) /* [out] */
1006 {
1007 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
1008 void* supportBuffer;
1009 ULARGE_INTEGER newSize;
1010 ULONG bytesWritten = 0;
1011
1012 if (pcbWritten == 0)
1013 pcbWritten = &bytesWritten;
1014 if (cb == 0)
1015 return S_OK;
1016 newSize.u.HighPart = 0;
1017 newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
1018 if (newSize.u.LowPart > This->streamSize.u.LowPart)
1019 IStream_SetSize(iface, newSize);
1020
1021 supportBuffer = GlobalLock(This->supportHandle);
1022 memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
1023 This->currentPosition.u.LowPart+=cb;
1024 *pcbWritten = cb;
1025 GlobalUnlock(This->supportHandle);
1026 return S_OK;
1027 }
1028
1029 static HRESULT WINAPI NoStatStreamImpl_Seek(
1030 IStream* iface,
1031 LARGE_INTEGER dlibMove, /* [in] */
1032 DWORD dwOrigin, /* [in] */
1033 ULARGE_INTEGER* plibNewPosition) /* [out] */
1034 {
1035 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
1036 ULARGE_INTEGER newPosition;
1037 switch (dwOrigin)
1038 {
1039 case STREAM_SEEK_SET:
1040 newPosition.u.HighPart = 0;
1041 newPosition.u.LowPart = 0;
1042 break;
1043 case STREAM_SEEK_CUR:
1044 newPosition = This->currentPosition;
1045 break;
1046 case STREAM_SEEK_END:
1047 newPosition = This->streamSize;
1048 break;
1049 default:
1050 return STG_E_INVALIDFUNCTION;
1051 }
1052 if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
1053 return STG_E_INVALIDFUNCTION;
1054 newPosition.QuadPart += dlibMove.QuadPart;
1055 if (plibNewPosition) *plibNewPosition = newPosition;
1056 This->currentPosition = newPosition;
1057 return S_OK;
1058 }
1059
1060 static HRESULT WINAPI NoStatStreamImpl_SetSize(
1061 IStream* iface,
1062 ULARGE_INTEGER libNewSize) /* [in] */
1063 {
1064 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
1065 HGLOBAL supportHandle;
1066 if (libNewSize.u.HighPart != 0)
1067 return STG_E_INVALIDFUNCTION;
1068 if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
1069 return S_OK;
1070 supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
1071 if (supportHandle == 0)
1072 return STG_E_MEDIUMFULL;
1073 This->supportHandle = supportHandle;
1074 This->streamSize.u.LowPart = libNewSize.u.LowPart;
1075 return S_OK;
1076 }
1077
1078 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
1079 IStream* iface,
1080 IStream* pstm, /* [unique][in] */
1081 ULARGE_INTEGER cb, /* [in] */
1082 ULARGE_INTEGER* pcbRead, /* [out] */
1083 ULARGE_INTEGER* pcbWritten) /* [out] */
1084 {
1085 HRESULT hr = S_OK;
1086 BYTE tmpBuffer[128];
1087 ULONG bytesRead, bytesWritten, copySize;
1088 ULARGE_INTEGER totalBytesRead;
1089 ULARGE_INTEGER totalBytesWritten;
1090
1091 if ( pstm == 0 )
1092 return STG_E_INVALIDPOINTER;
1093 totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
1094 totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
1095
1096 while ( cb.u.LowPart > 0 )
1097 {
1098 if ( cb.u.LowPart >= 128 )
1099 copySize = 128;
1100 else
1101 copySize = cb.u.LowPart;
1102 IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
1103 totalBytesRead.u.LowPart += bytesRead;
1104 IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
1105 totalBytesWritten.u.LowPart += bytesWritten;
1106 if (bytesRead != bytesWritten)
1107 {
1108 hr = STG_E_MEDIUMFULL;
1109 break;
1110 }
1111 if (bytesRead!=copySize)
1112 cb.u.LowPart = 0;
1113 else
1114 cb.u.LowPart -= bytesRead;
1115 }
1116 if (pcbRead)
1117 {
1118 pcbRead->u.LowPart = totalBytesRead.u.LowPart;
1119 pcbRead->u.HighPart = totalBytesRead.u.HighPart;
1120 }
1121
1122 if (pcbWritten)
1123 {
1124 pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
1125 pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
1126 }
1127 return hr;
1128 }
1129
1130 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
1131 {
1132 return S_OK;
1133 }
1134 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
1135
1136 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
1137 IStream* iface,
1138 ULARGE_INTEGER libOffset, /* [in] */
1139 ULARGE_INTEGER cb, /* [in] */
1140 DWORD dwLockType) /* [in] */
1141 {
1142 return S_OK;
1143 }
1144
1145 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
1146 IStream* iface,
1147 ULARGE_INTEGER libOffset, /* [in] */
1148 ULARGE_INTEGER cb, /* [in] */
1149 DWORD dwLockType) /* [in] */
1150 {
1151 return S_OK;
1152 }
1153
1154 static HRESULT WINAPI NoStatStreamImpl_Stat(
1155 IStream* iface,
1156 STATSTG* pstatstg, /* [out] */
1157 DWORD grfStatFlag) /* [in] */
1158 {
1159 return E_NOTIMPL;
1160 }
1161
1162 static HRESULT WINAPI NoStatStreamImpl_Clone(
1163 IStream* iface,
1164 IStream** ppstm) /* [out] */
1165 {
1166 return E_NOTIMPL;
1167 }
1168 static const IStreamVtbl NoStatStreamImpl_Vtbl;
1169
1170 /*
1171 Build an object that implements IStream, without IStream_Stat capabilities.
1172 Receives a memory handle with data buffer. If memory handle is non-null,
1173 it is assumed to be unlocked, otherwise an internal memory handle is allocated.
1174 In any case the object takes ownership of memory handle and will free it on
1175 object release.
1176 */
1177 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
1178 {
1179 NoStatStreamImpl* newStream;
1180
1181 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
1182 if (newStream!=0)
1183 {
1184 newStream->lpVtbl = &NoStatStreamImpl_Vtbl;
1185 newStream->ref = 1;
1186 newStream->supportHandle = hGlobal;
1187
1188 if (!newStream->supportHandle)
1189 newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
1190 GMEM_SHARE, 0);
1191 newStream->currentPosition.u.HighPart = 0;
1192 newStream->currentPosition.u.LowPart = 0;
1193 newStream->streamSize.u.HighPart = 0;
1194 newStream->streamSize.u.LowPart = GlobalSize(newStream->supportHandle);
1195 }
1196 return newStream;
1197 }
1198
1199
1200 static const IStreamVtbl NoStatStreamImpl_Vtbl =
1201 {
1202 NoStatStreamImpl_QueryInterface,
1203 NoStatStreamImpl_AddRef,
1204 NoStatStreamImpl_Release,
1205 NoStatStreamImpl_Read,
1206 NoStatStreamImpl_Write,
1207 NoStatStreamImpl_Seek,
1208 NoStatStreamImpl_SetSize,
1209 NoStatStreamImpl_CopyTo,
1210 NoStatStreamImpl_Commit,
1211 NoStatStreamImpl_Revert,
1212 NoStatStreamImpl_LockRegion,
1213 NoStatStreamImpl_UnlockRegion,
1214 NoStatStreamImpl_Stat,
1215 NoStatStreamImpl_Clone
1216 };