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