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