Sync trunk r40500
[reactos.git] / rostests / 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 #include <time.h>
27
28 #define COBJMACROS
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 <wtypes.h>
40 #include <olectl.h>
41 #include <objidl.h>
42
43 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
44
45 #define ole_expect(expr, expect) { \
46 HRESULT r = expr; \
47 ok(r == (expect), #expr " returned %x, expected %s (%x)\n", r, #expect, expect); \
48 }
49
50 #define ole_check(expr) ole_expect(expr, S_OK);
51
52 static HMODULE hOleaut32;
53
54 static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);
55 static HRESULT (WINAPI *pOleCreatePictureIndirect)(PICTDESC*,REFIID,BOOL,LPVOID*);
56
57 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
58
59 /* 1x1 pixel gif */
60 static const unsigned char gifimage[35] = {
61 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
62 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
63 0x01,0x00,0x3b
64 };
65
66 /* 1x1 pixel jpg */
67 static const unsigned char jpgimage[285] = {
68 0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
69 0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
70 0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
71 0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
72 0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
73 0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
74 0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
75 0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,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,0xff,0xc0,
78 0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
79 0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
80 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
81 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
82 0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
83 0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
84 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
85 0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
86 };
87
88 /* 1x1 pixel png */
89 static const unsigned char pngimage[285] = {
90 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
91 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
92 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
93 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
94 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
95 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
96 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
97 };
98
99 /* 1x1 pixel bmp */
100 static const unsigned char bmpimage[66] = {
101 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
102 0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
103 0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
104 0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
105 0x00,0x00
106 };
107
108 /* 2x2 pixel gif */
109 static const unsigned char gif4pixel[42] = {
110 0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
111 0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
112 0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
113 };
114
115 /* APM with an empty metafile with some padding zeros - looks like under Window the
116 * metafile data should be at least 20 bytes */
117 static const unsigned char apmdata[] = {
118 0xd7,0xcd,0xc6,0x9a, 0x00,0x00,0x00,0x00, 0x00,0x00,0xee,0x02, 0xb1,0x03,0xa0,0x05,
119 0x00,0x00,0x00,0x00, 0xee,0x53,0x01,0x00, 0x09,0x00,0x00,0x03, 0x13,0x00,0x00,0x00,
120 0x01,0x00,0x05,0x00, 0x00,0x00,0x00,0x00, 0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
121 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
122 };
123
124 struct NoStatStreamImpl
125 {
126 const IStreamVtbl *lpVtbl;
127 LONG ref;
128
129 HGLOBAL supportHandle;
130 ULARGE_INTEGER streamSize;
131 ULARGE_INTEGER currentPosition;
132 };
133 typedef struct NoStatStreamImpl NoStatStreamImpl;
134 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal);
135
136 static void
137 test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
138 {
139 IPicture* pic = NULL;
140 HRESULT hres;
141 LPVOID pvObj = NULL;
142 OLE_HANDLE handle, hPal;
143 OLE_XSIZE_HIMETRIC width;
144 OLE_YSIZE_HIMETRIC height;
145 short type;
146 DWORD attr;
147 ULONG res;
148
149 pvObj = NULL;
150 hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
151 pic = pvObj;
152
153 ok(hres == S_OK,"OLP (NULL,..) does not return 0, but 0x%08x\n",hres);
154 ok(pic != NULL,"OLP (NULL,..) returns NULL, instead of !NULL\n");
155 if (pic == NULL)
156 return;
157
158 pvObj = NULL;
159 hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);
160
161 ok(hres == S_OK,"IPicture_QI does not return S_OK, but 0x%08x\n", hres);
162 ok(pvObj != NULL,"IPicture_QI does return NULL, instead of a ptr\n");
163
164 IPicture_Release ((IPicture*)pvObj);
165
166 handle = 0;
167 hres = IPicture_get_Handle (pic, &handle);
168 ok(hres == S_OK,"IPicture_get_Handle does not return S_OK, but 0x%08x\n", hres);
169 ok(handle != 0, "IPicture_get_Handle returns a NULL handle, but it should be non NULL\n");
170
171 width = 0;
172 hres = IPicture_get_Width (pic, &width);
173 ok(hres == S_OK,"IPicture_get_Width does not return S_OK, but 0x%08x\n", hres);
174 ok(width != 0, "IPicture_get_Width returns 0, but it should not be 0.\n");
175
176 height = 0;
177 hres = IPicture_get_Height (pic, &height);
178 ok(hres == S_OK,"IPicture_get_Height does not return S_OK, but 0x%08x\n", hres);
179 ok(height != 0, "IPicture_get_Height returns 0, but it should not be 0.\n");
180
181 type = 0;
182 hres = IPicture_get_Type (pic, &type);
183 ok(hres == S_OK,"IPicture_get_Type does not return S_OK, but 0x%08x\n", hres);
184 ok(type == PICTYPE_BITMAP, "IPicture_get_Type returns %d, but it should be PICTYPE_BITMAP(%d).\n", type, PICTYPE_BITMAP);
185
186 attr = 0;
187 hres = IPicture_get_Attributes (pic, &attr);
188 ok(hres == S_OK,"IPicture_get_Attributes does not return S_OK, but 0x%08x\n", hres);
189 ok(attr == 0, "IPicture_get_Attributes returns %d, but it should be 0.\n", attr);
190
191 hPal = 0;
192 hres = IPicture_get_hPal (pic, &hPal);
193 ok(hres == S_OK,"IPicture_get_hPal does not return S_OK, but 0x%08x\n", hres);
194 /* a single pixel b/w image has no palette */
195 ok(hPal == 0, "IPicture_get_hPal returns %d, but it should be 0.\n", hPal);
196
197 res = IPicture_Release (pic);
198 ok (res == 0, "refcount after release is %d, but should be 0?\n", res);
199 }
200
201 static void
202 test_pic(const unsigned char *imgdata, unsigned int imgsize)
203 {
204 LPSTREAM stream;
205 HGLOBAL hglob;
206 LPBYTE data;
207 HRESULT hres;
208 LARGE_INTEGER seekto;
209 ULARGE_INTEGER newpos1;
210 DWORD * header;
211 unsigned int i,j;
212
213 /* Let the fun begin */
214 hglob = GlobalAlloc (0, imgsize);
215 data = GlobalLock (hglob);
216 memcpy(data, imgdata, imgsize);
217 GlobalUnlock(hglob); data = NULL;
218
219 hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
220 ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
221
222 memset(&seekto,0,sizeof(seekto));
223 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
224 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
225 test_pic_with_stream(stream, imgsize);
226
227 IStream_Release(stream);
228
229 /* again with Non Statable and Non Seekable stream */
230 stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
231 hglob = 0; /* Non-statable impl always deletes on release */
232 test_pic_with_stream(stream, 0);
233
234 IStream_Release(stream);
235 for (i = 1; i <= 8; i++) {
236 /* more fun!!! */
237 hglob = GlobalAlloc (0, imgsize + i * (2 * sizeof(DWORD)));
238 data = GlobalLock (hglob);
239 header = (DWORD *)data;
240
241 /* multiple copies of header */
242 memcpy(data,"lt\0\0",4);
243 header[1] = imgsize;
244 for (j = 2; j <= i; j++) {
245 memcpy(&(header[2 * (j - 1)]), header, 2 * sizeof(DWORD));
246 }
247 memcpy(data + i * (2 * sizeof(DWORD)), imgdata, imgsize);
248 GlobalUnlock(hglob); data = NULL;
249
250 hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
251 ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08x\n", hres);
252
253 memset(&seekto,0,sizeof(seekto));
254 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
255 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
256 test_pic_with_stream(stream, imgsize);
257
258 IStream_Release(stream);
259
260 /* again with Non Statable and Non Seekable stream */
261 stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
262 hglob = 0; /* Non-statable impl always deletes on release */
263 test_pic_with_stream(stream, 0);
264
265 IStream_Release(stream);
266 }
267 }
268
269 static void test_empty_image(void) {
270 LPBYTE data;
271 LPSTREAM stream;
272 IPicture* pic = NULL;
273 HRESULT hres;
274 LPVOID pvObj = NULL;
275 HGLOBAL hglob;
276 OLE_HANDLE handle;
277 ULARGE_INTEGER newpos1;
278 LARGE_INTEGER seekto;
279 short type;
280
281 /* Empty image. Happens occasionally in VB programs. */
282 hglob = GlobalAlloc (0, 8);
283 data = GlobalLock (hglob);
284 memcpy(data,"lt\0\0",4);
285 ((DWORD*)data)[1] = 0;
286 hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
287 ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
288
289 memset(&seekto,0,sizeof(seekto));
290 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
291 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
292
293 pvObj = NULL;
294 hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
295 pic = pvObj;
296 ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
297 ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
298
299 hres = IPicture_get_Type (pic, &type);
300 ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
301 ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
302
303 hres = IPicture_get_Handle (pic, &handle);
304 ok (hres == S_OK,"empty picture get handle failed with hres 0x%08x\n", hres);
305 ok (handle == 0, "empty picture get handle did not return 0, but 0x%08x\n", handle);
306 IPicture_Release (pic);
307 }
308
309 static void test_empty_image_2(void) {
310 LPBYTE data;
311 LPSTREAM stream;
312 IPicture* pic = NULL;
313 HRESULT hres;
314 LPVOID pvObj = NULL;
315 HGLOBAL hglob;
316 ULARGE_INTEGER newpos1;
317 LARGE_INTEGER seekto;
318 short type;
319
320 /* Empty image at random stream position. */
321 hglob = GlobalAlloc (0, 200);
322 data = GlobalLock (hglob);
323 data += 42;
324 memcpy(data,"lt\0\0",4);
325 ((DWORD*)data)[1] = 0;
326 hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
327 ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08x\n", hres);
328
329 memset(&seekto,0,sizeof(seekto));
330 seekto.u.LowPart = 42;
331 hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
332 ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08x\n", hres);
333
334 pvObj = NULL;
335 hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
336 pic = pvObj;
337 ok(hres == S_OK,"empty picture not loaded, hres 0x%08x\n", hres);
338 ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
339
340 hres = IPicture_get_Type (pic, &type);
341 ok (hres == S_OK,"empty picture get type failed with hres 0x%08x\n", hres);
342 ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
343
344 IPicture_Release (pic);
345 }
346
347 static void test_Invoke(void)
348 {
349 IPictureDisp *picdisp;
350 HRESULT hr;
351 VARIANTARG vararg;
352 DISPPARAMS dispparams;
353 VARIANT varresult;
354 IStream *stream;
355 HGLOBAL hglob;
356 void *data;
357
358 hglob = GlobalAlloc (0, sizeof(gifimage));
359 data = GlobalLock(hglob);
360 memcpy(data, gifimage, sizeof(gifimage));
361 GlobalUnlock(hglob);
362
363 hr = CreateStreamOnHGlobal (hglob, FALSE, &stream);
364 ok_ole_success(hr, "CreateStreamOnHGlobal");
365
366 hr = pOleLoadPicture(stream, sizeof(gifimage), TRUE, &IID_IPictureDisp, (void **)&picdisp);
367 IStream_Release(stream);
368 ok_ole_success(hr, "OleLoadPicture");
369
370 V_VT(&vararg) = VT_BOOL;
371 V_BOOL(&vararg) = VARIANT_FALSE;
372 dispparams.cNamedArgs = 0;
373 dispparams.rgdispidNamedArgs = NULL;
374 dispparams.cArgs = 1;
375 dispparams.rgvarg = &vararg;
376 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IPictureDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
377 ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
378 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IUnknown, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
379 ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08x\n", hr);
380
381 dispparams.cArgs = 0;
382 dispparams.rgvarg = NULL;
383 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
384 ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
385
386 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, NULL, NULL, NULL, NULL);
387 ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
388
389 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, NULL, NULL, NULL);
390 ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
391
392 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
393 ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
394
395 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
396 ok_ole_success(hr, "IPictureDisp_Invoke");
397 ok(V_VT(&varresult) == VT_I4, "V_VT(&varresult) should have been VT_UINT instead of %d\n", V_VT(&varresult));
398
399 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
400 ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
401
402 hr = IPictureDisp_Invoke(picdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
403 ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
404
405 dispparams.cArgs = 1;
406 dispparams.rgvarg = &vararg;
407 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
408 ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
409
410 dispparams.cArgs = 1;
411 dispparams.rgvarg = &vararg;
412 hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
413 ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
414
415 IPictureDisp_Release(picdisp);
416 }
417
418 static void test_OleCreatePictureIndirect(void)
419 {
420 IPicture *pict;
421 HRESULT hr;
422 short type;
423 OLE_HANDLE handle;
424
425 if(!pOleCreatePictureIndirect)
426 {
427 skip("Skipping OleCreatePictureIndirect tests\n");
428 return;
429 }
430
431 hr = pOleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
432 ok(hr == S_OK, "hr %08x\n", hr);
433
434 hr = IPicture_get_Type(pict, &type);
435 ok(hr == S_OK, "hr %08x\n", hr);
436 ok(type == PICTYPE_UNINITIALIZED, "type %d\n", type);
437
438 hr = IPicture_get_Handle(pict, &handle);
439 ok(hr == S_OK, "hr %08x\n", hr);
440 ok(handle == 0, "handle %08x\n", handle);
441
442 IPicture_Release(pict);
443 }
444
445 static void test_apm()
446 {
447 OLE_HANDLE handle;
448 LPSTREAM stream;
449 IPicture *pict;
450 HGLOBAL hglob;
451 LPBYTE *data;
452 LONG cxy;
453 BOOL keep;
454 short type;
455
456 hglob = GlobalAlloc (0, sizeof(apmdata));
457 data = GlobalLock(hglob);
458 memcpy(data, apmdata, sizeof(apmdata));
459
460 ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
461 ole_check(OleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
462
463 ole_check(IPicture_get_Handle(pict, &handle));
464 ok(handle != 0, "handle is null\n");
465
466 ole_check(IPicture_get_Type(pict, &type));
467 expect_eq(type, PICTYPE_METAFILE, short, "%d");
468
469 ole_check(IPicture_get_Height(pict, &cxy));
470 expect_eq(cxy, 1667, LONG, "%d");
471
472 ole_check(IPicture_get_Width(pict, &cxy));
473 expect_eq(cxy, 1323, LONG, "%d");
474
475 ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
476 todo_wine expect_eq(keep, FALSE, LONG, "%d");
477
478 ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
479 IPicture_Release(pict);
480 IStream_Release(stream);
481 }
482
483 START_TEST(olepicture)
484 {
485 hOleaut32 = GetModuleHandleA("oleaut32.dll");
486 pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
487 pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect");
488 if (!pOleLoadPicture)
489 {
490 skip("OleLoadPicture is not available\n");
491 return;
492 }
493
494 /* Test regular 1x1 pixel images of gif, jpg, bmp type */
495 test_pic(gifimage, sizeof(gifimage));
496 test_pic(jpgimage, sizeof(jpgimage));
497 test_pic(bmpimage, sizeof(bmpimage));
498 test_pic(gif4pixel, sizeof(gif4pixel));
499 /* FIXME: No PNG support yet in Wine or in older Windows... */
500 if (0) test_pic(pngimage, sizeof(pngimage));
501 test_empty_image();
502 test_empty_image_2();
503 test_apm();
504
505 test_Invoke();
506 test_OleCreatePictureIndirect();
507 }
508
509
510 /* Helper functions only ... */
511
512
513 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
514 {
515 GlobalFree(This->supportHandle);
516 This->supportHandle=0;
517 HeapFree(GetProcessHeap(), 0, This);
518 }
519
520 static ULONG WINAPI NoStatStreamImpl_AddRef(
521 IStream* iface)
522 {
523 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
524 return InterlockedIncrement(&This->ref);
525 }
526
527 static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
528 IStream* iface,
529 REFIID riid, /* [in] */
530 void** ppvObject) /* [iid_is][out] */
531 {
532 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
533 if (ppvObject==0) return E_INVALIDARG;
534 *ppvObject = 0;
535 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
536 {
537 *ppvObject = (IStream*)This;
538 }
539 else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
540 {
541 *ppvObject = (IStream*)This;
542 }
543
544 if ((*ppvObject)==0)
545 return E_NOINTERFACE;
546 NoStatStreamImpl_AddRef(iface);
547 return S_OK;
548 }
549
550 static ULONG WINAPI NoStatStreamImpl_Release(
551 IStream* iface)
552 {
553 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
554 ULONG newRef = InterlockedDecrement(&This->ref);
555 if (newRef==0)
556 NoStatStreamImpl_Destroy(This);
557 return newRef;
558 }
559
560 static HRESULT WINAPI NoStatStreamImpl_Read(
561 IStream* iface,
562 void* pv, /* [length_is][size_is][out] */
563 ULONG cb, /* [in] */
564 ULONG* pcbRead) /* [out] */
565 {
566 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
567 void* supportBuffer;
568 ULONG bytesReadBuffer;
569 ULONG bytesToReadFromBuffer;
570
571 if (pcbRead==0)
572 pcbRead = &bytesReadBuffer;
573 bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
574 supportBuffer = GlobalLock(This->supportHandle);
575 memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
576 This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
577 *pcbRead = bytesToReadFromBuffer;
578 GlobalUnlock(This->supportHandle);
579 if(*pcbRead == cb)
580 return S_OK;
581 return S_FALSE;
582 }
583
584 static HRESULT WINAPI NoStatStreamImpl_Write(
585 IStream* iface,
586 const void* pv, /* [size_is][in] */
587 ULONG cb, /* [in] */
588 ULONG* pcbWritten) /* [out] */
589 {
590 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
591 void* supportBuffer;
592 ULARGE_INTEGER newSize;
593 ULONG bytesWritten = 0;
594
595 if (pcbWritten == 0)
596 pcbWritten = &bytesWritten;
597 if (cb == 0)
598 return S_OK;
599 newSize.u.HighPart = 0;
600 newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
601 if (newSize.u.LowPart > This->streamSize.u.LowPart)
602 IStream_SetSize(iface, newSize);
603
604 supportBuffer = GlobalLock(This->supportHandle);
605 memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
606 This->currentPosition.u.LowPart+=cb;
607 *pcbWritten = cb;
608 GlobalUnlock(This->supportHandle);
609 return S_OK;
610 }
611
612 static HRESULT WINAPI NoStatStreamImpl_Seek(
613 IStream* iface,
614 LARGE_INTEGER dlibMove, /* [in] */
615 DWORD dwOrigin, /* [in] */
616 ULARGE_INTEGER* plibNewPosition) /* [out] */
617 {
618 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
619 ULARGE_INTEGER newPosition;
620 switch (dwOrigin)
621 {
622 case STREAM_SEEK_SET:
623 newPosition.u.HighPart = 0;
624 newPosition.u.LowPart = 0;
625 break;
626 case STREAM_SEEK_CUR:
627 newPosition = This->currentPosition;
628 break;
629 case STREAM_SEEK_END:
630 newPosition = This->streamSize;
631 break;
632 default:
633 return STG_E_INVALIDFUNCTION;
634 }
635 if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
636 return STG_E_INVALIDFUNCTION;
637 newPosition.QuadPart += dlibMove.QuadPart;
638 if (plibNewPosition) *plibNewPosition = newPosition;
639 This->currentPosition = newPosition;
640 return S_OK;
641 }
642
643 static HRESULT WINAPI NoStatStreamImpl_SetSize(
644 IStream* iface,
645 ULARGE_INTEGER libNewSize) /* [in] */
646 {
647 NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
648 HGLOBAL supportHandle;
649 if (libNewSize.u.HighPart != 0)
650 return STG_E_INVALIDFUNCTION;
651 if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
652 return S_OK;
653 supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
654 if (supportHandle == 0)
655 return STG_E_MEDIUMFULL;
656 This->supportHandle = supportHandle;
657 This->streamSize.u.LowPart = libNewSize.u.LowPart;
658 return S_OK;
659 }
660
661 static HRESULT WINAPI NoStatStreamImpl_CopyTo(
662 IStream* iface,
663 IStream* pstm, /* [unique][in] */
664 ULARGE_INTEGER cb, /* [in] */
665 ULARGE_INTEGER* pcbRead, /* [out] */
666 ULARGE_INTEGER* pcbWritten) /* [out] */
667 {
668 HRESULT hr = S_OK;
669 BYTE tmpBuffer[128];
670 ULONG bytesRead, bytesWritten, copySize;
671 ULARGE_INTEGER totalBytesRead;
672 ULARGE_INTEGER totalBytesWritten;
673
674 if ( pstm == 0 )
675 return STG_E_INVALIDPOINTER;
676 totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
677 totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
678
679 while ( cb.u.LowPart > 0 )
680 {
681 if ( cb.u.LowPart >= 128 )
682 copySize = 128;
683 else
684 copySize = cb.u.LowPart;
685 IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
686 totalBytesRead.u.LowPart += bytesRead;
687 IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
688 totalBytesWritten.u.LowPart += bytesWritten;
689 if (bytesRead != bytesWritten)
690 {
691 hr = STG_E_MEDIUMFULL;
692 break;
693 }
694 if (bytesRead!=copySize)
695 cb.u.LowPart = 0;
696 else
697 cb.u.LowPart -= bytesRead;
698 }
699 if (pcbRead)
700 {
701 pcbRead->u.LowPart = totalBytesRead.u.LowPart;
702 pcbRead->u.HighPart = totalBytesRead.u.HighPart;
703 }
704
705 if (pcbWritten)
706 {
707 pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
708 pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
709 }
710 return hr;
711 }
712
713 static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
714 {
715 return S_OK;
716 }
717 static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
718
719 static HRESULT WINAPI NoStatStreamImpl_LockRegion(
720 IStream* iface,
721 ULARGE_INTEGER libOffset, /* [in] */
722 ULARGE_INTEGER cb, /* [in] */
723 DWORD dwLockType) /* [in] */
724 {
725 return S_OK;
726 }
727
728 static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
729 IStream* iface,
730 ULARGE_INTEGER libOffset, /* [in] */
731 ULARGE_INTEGER cb, /* [in] */
732 DWORD dwLockType) /* [in] */
733 {
734 return S_OK;
735 }
736
737 static HRESULT WINAPI NoStatStreamImpl_Stat(
738 IStream* iface,
739 STATSTG* pstatstg, /* [out] */
740 DWORD grfStatFlag) /* [in] */
741 {
742 return E_NOTIMPL;
743 }
744
745 static HRESULT WINAPI NoStatStreamImpl_Clone(
746 IStream* iface,
747 IStream** ppstm) /* [out] */
748 {
749 return E_NOTIMPL;
750 }
751 static const IStreamVtbl NoStatStreamImpl_Vtbl;
752
753 /*
754 Build an object that implements IStream, without IStream_Stat capabilities.
755 Receives a memory handle with data buffer. If memory handle is non-null,
756 it is assumed to be unlocked, otherwise an internal memory handle is allocated.
757 In any case the object takes ownership of memory handle and will free it on
758 object release.
759 */
760 static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
761 {
762 NoStatStreamImpl* newStream;
763
764 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
765 if (newStream!=0)
766 {
767 newStream->lpVtbl = &NoStatStreamImpl_Vtbl;
768 newStream->ref = 1;
769 newStream->supportHandle = hGlobal;
770
771 if (!newStream->supportHandle)
772 newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
773 GMEM_SHARE, 0);
774 newStream->currentPosition.u.HighPart = 0;
775 newStream->currentPosition.u.LowPart = 0;
776 newStream->streamSize.u.HighPart = 0;
777 newStream->streamSize.u.LowPart = GlobalSize(newStream->supportHandle);
778 }
779 return newStream;
780 }
781
782
783 static const IStreamVtbl NoStatStreamImpl_Vtbl =
784 {
785 NoStatStreamImpl_QueryInterface,
786 NoStatStreamImpl_AddRef,
787 NoStatStreamImpl_Release,
788 NoStatStreamImpl_Read,
789 NoStatStreamImpl_Write,
790 NoStatStreamImpl_Seek,
791 NoStatStreamImpl_SetSize,
792 NoStatStreamImpl_CopyTo,
793 NoStatStreamImpl_Commit,
794 NoStatStreamImpl_Revert,
795 NoStatStreamImpl_LockRegion,
796 NoStatStreamImpl_UnlockRegion,
797 NoStatStreamImpl_Stat,
798 NoStatStreamImpl_Clone
799 };