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