1739 lines
58 KiB
C
1739 lines
58 KiB
C
/*
|
|
* OLEPICTURE test program
|
|
*
|
|
* Copyright 2005 Marcus Meissner
|
|
* Copyright 2012 Dmitry Timoshkov
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <float.h>
|
|
|
|
#define COBJMACROS
|
|
#define CONST_VTABLE
|
|
#define NONAMELESSUNION
|
|
|
|
#include "wine/test.h"
|
|
#include <windef.h>
|
|
#include <winbase.h>
|
|
#include <winuser.h>
|
|
#include <wingdi.h>
|
|
#include <winnls.h>
|
|
#include <winerror.h>
|
|
#include <winnt.h>
|
|
|
|
#include <urlmon.h>
|
|
#include <wtypes.h>
|
|
#include <olectl.h>
|
|
#include <objidl.h>
|
|
|
|
#define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
|
|
|
|
#define ole_expect(expr, expect) { \
|
|
HRESULT r = expr; \
|
|
ok(r == (expect), #expr " returned %lx, expected %s (%lx)\n", r, #expect, expect); \
|
|
}
|
|
|
|
#define ole_check(expr) ole_expect(expr, S_OK);
|
|
|
|
static HMODULE hOleaut32;
|
|
|
|
static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);
|
|
static HRESULT (WINAPI *pOleLoadPictureEx)(LPSTREAM,LONG,BOOL,REFIID,DWORD,DWORD,DWORD,LPVOID*);
|
|
|
|
#define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error %#08lx\n", hr)
|
|
|
|
/* 1x1 pixel gif */
|
|
static const unsigned char gifimage[35] = {
|
|
0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
|
|
0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
|
|
0x01,0x00,0x3b
|
|
};
|
|
|
|
/* 1x1 pixel jpg */
|
|
static const unsigned char jpgimage[285] = {
|
|
0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
|
|
0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
|
|
0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
|
|
0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
|
|
0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
|
|
0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
|
|
0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
|
|
0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
|
|
0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
|
|
0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
|
|
0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
|
|
0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
|
|
0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
|
|
0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
|
|
};
|
|
|
|
/* 1x1 pixel png */
|
|
static const unsigned char pngimage[285] = {
|
|
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
|
|
0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
|
|
0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
|
|
0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
|
|
0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
|
|
0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
|
|
0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
|
|
};
|
|
|
|
/* 1x1 pixel bmp */
|
|
static const unsigned char bmpimage[66] = {
|
|
0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
|
|
0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
|
|
0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
|
|
0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
|
|
0x00,0x00
|
|
};
|
|
|
|
/* 2x2 pixel gif */
|
|
static const unsigned char gif4pixel[42] = {
|
|
0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
|
|
0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
|
|
0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
|
|
};
|
|
|
|
/* APM with an empty metafile with some padding zeros - looks like under Window the
|
|
* metafile data should be at least 20 bytes */
|
|
static const unsigned char apmdata[] = {
|
|
0xd7,0xcd,0xc6,0x9a, 0x00,0x00,0x00,0x00, 0x00,0x00,0xee,0x02, 0xb1,0x03,0xa0,0x05,
|
|
0x00,0x00,0x00,0x00, 0xee,0x53,0x01,0x00, 0x09,0x00,0x00,0x03, 0x13,0x00,0x00,0x00,
|
|
0x01,0x00,0x05,0x00, 0x00,0x00,0x00,0x00, 0x03,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00
|
|
};
|
|
|
|
/* MF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
|
|
static const unsigned char metafile[] = {
|
|
0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x19, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x0a,
|
|
0x16, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00,
|
|
0x54, 0x65, 0x73, 0x74, 0x03, 0x00, 0x05, 0x00,
|
|
0x08, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00,
|
|
0x00, 0x00
|
|
};
|
|
|
|
/* EMF_TEXTOUT_ON_PATH_BITS from gdi32/tests/metafile.c */
|
|
static const unsigned char enhmetafile[] = {
|
|
0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xe7, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff,
|
|
0x20, 0x45, 0x4d, 0x46, 0x00, 0x00, 0x01, 0x00,
|
|
0xf4, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
|
|
0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x04, 0x00,
|
|
0x80, 0xa9, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00,
|
|
0x08, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
|
|
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0xc8, 0x41, 0x00, 0x80, 0xbb, 0x41,
|
|
0x0b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
|
|
0x04, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00,
|
|
0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
|
|
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
|
0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
|
0x3c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
|
0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
|
0x14, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
static HBITMAP stock_bm;
|
|
|
|
static HDC create_render_dc( void )
|
|
{
|
|
HDC dc = CreateCompatibleDC( NULL );
|
|
BITMAPINFO info = {{sizeof(info.bmiHeader), 100, 100, 1, 32, BI_RGB }};
|
|
void *bits;
|
|
HBITMAP dib = CreateDIBSection( NULL, &info, DIB_RGB_COLORS, &bits, NULL, 0 );
|
|
|
|
stock_bm = SelectObject( dc, dib );
|
|
return dc;
|
|
}
|
|
|
|
static void delete_render_dc( HDC dc )
|
|
{
|
|
HBITMAP dib = SelectObject( dc, stock_bm );
|
|
DeleteObject( dib );
|
|
DeleteDC( dc );
|
|
}
|
|
|
|
typedef struct NoStatStreamImpl
|
|
{
|
|
IStream IStream_iface;
|
|
LONG ref;
|
|
|
|
HGLOBAL supportHandle;
|
|
ULARGE_INTEGER streamSize;
|
|
ULARGE_INTEGER currentPosition;
|
|
} NoStatStreamImpl;
|
|
|
|
static IStream* NoStatStream_Construct(HGLOBAL hGlobal);
|
|
|
|
static void
|
|
test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
|
|
{
|
|
IPicture* pic = NULL;
|
|
HRESULT hres;
|
|
LPVOID pvObj = NULL;
|
|
OLE_HANDLE handle, hPal;
|
|
OLE_XSIZE_HIMETRIC width;
|
|
OLE_YSIZE_HIMETRIC height;
|
|
short type;
|
|
DWORD attr;
|
|
ULONG res;
|
|
|
|
pvObj = NULL;
|
|
hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
|
|
pic = pvObj;
|
|
|
|
ok(hres == S_OK,"OLP (NULL,..) does not return 0, but 0x%08lx\n",hres);
|
|
ok(pic != NULL,"OLP (NULL,..) returns NULL, instead of !NULL\n");
|
|
if (pic == NULL)
|
|
return;
|
|
|
|
pvObj = NULL;
|
|
hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);
|
|
|
|
ok(hres == S_OK,"IPicture_QI does not return S_OK, but 0x%08lx\n", hres);
|
|
ok(pvObj != NULL,"IPicture_QI does return NULL, instead of a ptr\n");
|
|
|
|
IPicture_Release ((IPicture*)pvObj);
|
|
|
|
handle = 0;
|
|
hres = IPicture_get_Handle (pic, &handle);
|
|
ok(hres == S_OK,"IPicture_get_Handle does not return S_OK, but 0x%08lx\n", hres);
|
|
ok(handle != 0, "IPicture_get_Handle returns a NULL handle, but it should be non NULL\n");
|
|
|
|
if (handle)
|
|
{
|
|
BITMAP bmp;
|
|
GetObjectA(UlongToHandle(handle), sizeof(BITMAP), &bmp);
|
|
todo_wine ok(bmp.bmBits != 0, "not a dib\n");
|
|
}
|
|
|
|
width = 0;
|
|
hres = IPicture_get_Width (pic, &width);
|
|
ok(hres == S_OK,"IPicture_get_Width does not return S_OK, but 0x%08lx\n", hres);
|
|
ok(width != 0, "IPicture_get_Width returns 0, but it should not be 0.\n");
|
|
|
|
height = 0;
|
|
hres = IPicture_get_Height (pic, &height);
|
|
ok(hres == S_OK,"IPicture_get_Height does not return S_OK, but 0x%08lx\n", hres);
|
|
ok(height != 0, "IPicture_get_Height returns 0, but it should not be 0.\n");
|
|
|
|
type = 0;
|
|
hres = IPicture_get_Type (pic, &type);
|
|
ok(hres == S_OK,"IPicture_get_Type does not return S_OK, but 0x%08lx\n", hres);
|
|
ok(type == PICTYPE_BITMAP, "IPicture_get_Type returns %d, but it should be PICTYPE_BITMAP(%d).\n", type, PICTYPE_BITMAP);
|
|
|
|
attr = 0;
|
|
hres = IPicture_get_Attributes (pic, &attr);
|
|
ok(hres == S_OK,"IPicture_get_Attributes does not return S_OK, but 0x%08lx\n", hres);
|
|
ok(attr == 0, "IPicture_get_Attributes returns %ld, but it should be 0.\n", attr);
|
|
|
|
hPal = 0;
|
|
hres = IPicture_get_hPal (pic, &hPal);
|
|
ok(hres == S_OK,"IPicture_get_hPal does not return S_OK, but 0x%08lx\n", hres);
|
|
/* a single pixel b/w image has no palette */
|
|
ok(hPal == 0, "IPicture_get_hPal returns %d, but it should be 0.\n", hPal);
|
|
|
|
res = IPicture_Release (pic);
|
|
ok (res == 0, "refcount after release is %ld, but should be 0?\n", res);
|
|
}
|
|
|
|
static void
|
|
test_pic(const unsigned char *imgdata, unsigned int imgsize)
|
|
{
|
|
LPSTREAM stream;
|
|
HGLOBAL hglob;
|
|
LPBYTE data;
|
|
HRESULT hres;
|
|
LARGE_INTEGER seekto;
|
|
ULARGE_INTEGER newpos1;
|
|
DWORD * header;
|
|
unsigned int i,j;
|
|
|
|
/* Let the fun begin */
|
|
hglob = GlobalAlloc (0, imgsize);
|
|
data = GlobalLock (hglob);
|
|
memcpy(data, imgdata, imgsize);
|
|
GlobalUnlock(hglob); data = NULL;
|
|
|
|
hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
|
|
ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08lx\n", hres);
|
|
|
|
memset(&seekto,0,sizeof(seekto));
|
|
hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
|
|
ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
|
|
test_pic_with_stream(stream, imgsize);
|
|
|
|
IStream_Release(stream);
|
|
|
|
/* again with Non Statable and Non Seekable stream */
|
|
stream = NoStatStream_Construct(hglob);
|
|
hglob = 0; /* Non-statable impl always deletes on release */
|
|
test_pic_with_stream(stream, 0);
|
|
|
|
IStream_Release(stream);
|
|
for (i = 1; i <= 8; i++) {
|
|
/* more fun!!! */
|
|
hglob = GlobalAlloc (0, imgsize + i * (2 * sizeof(DWORD)));
|
|
data = GlobalLock (hglob);
|
|
header = (DWORD *)data;
|
|
|
|
/* multiple copies of header */
|
|
memcpy(data,"lt\0\0",4);
|
|
header[1] = imgsize;
|
|
for (j = 2; j <= i; j++) {
|
|
memcpy(&(header[2 * (j - 1)]), header, 2 * sizeof(DWORD));
|
|
}
|
|
memcpy(data + i * (2 * sizeof(DWORD)), imgdata, imgsize);
|
|
GlobalUnlock(hglob); data = NULL;
|
|
|
|
hres = CreateStreamOnHGlobal (hglob, FALSE, &stream);
|
|
ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08lx\n", hres);
|
|
|
|
memset(&seekto,0,sizeof(seekto));
|
|
hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
|
|
ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
|
|
test_pic_with_stream(stream, imgsize);
|
|
|
|
IStream_Release(stream);
|
|
|
|
/* again with Non Statable and Non Seekable stream */
|
|
stream = NoStatStream_Construct(hglob);
|
|
hglob = 0; /* Non-statable impl always deletes on release */
|
|
test_pic_with_stream(stream, 0);
|
|
|
|
IStream_Release(stream);
|
|
}
|
|
}
|
|
|
|
static void test_empty_image(void) {
|
|
LPBYTE data;
|
|
LPSTREAM stream;
|
|
IPicture* pic = NULL;
|
|
HRESULT hres;
|
|
LPVOID pvObj = NULL;
|
|
HGLOBAL hglob;
|
|
OLE_HANDLE handle;
|
|
ULARGE_INTEGER newpos1;
|
|
LARGE_INTEGER seekto;
|
|
short type;
|
|
DWORD attr;
|
|
|
|
/* Empty image. Happens occasionally in VB programs. */
|
|
hglob = GlobalAlloc (0, 8);
|
|
data = GlobalLock (hglob);
|
|
memcpy(data,"lt\0\0",4);
|
|
((DWORD*)data)[1] = 0;
|
|
hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
|
|
ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08lx\n", hres);
|
|
|
|
memset(&seekto,0,sizeof(seekto));
|
|
hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
|
|
ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
|
|
|
|
pvObj = NULL;
|
|
hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
|
|
pic = pvObj;
|
|
ok(hres == S_OK,"empty picture not loaded, hres 0x%08lx\n", hres);
|
|
ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
|
|
|
|
hres = IPicture_get_Type (pic, &type);
|
|
ok (hres == S_OK,"empty picture get type failed with hres 0x%08lx\n", hres);
|
|
ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
|
|
|
|
attr = 0xdeadbeef;
|
|
hres = IPicture_get_Attributes (pic, &attr);
|
|
ok (hres == S_OK,"empty picture get attributes failed with hres 0x%08lx\n", hres);
|
|
ok (attr == 0,"attr is %ld, but should be 0\n", attr);
|
|
|
|
hres = IPicture_get_Handle (pic, &handle);
|
|
ok (hres == S_OK,"empty picture get handle failed with hres 0x%08lx\n", hres);
|
|
ok (handle == 0, "empty picture get handle did not return 0, but 0x%08x\n", handle);
|
|
IPicture_Release (pic);
|
|
IStream_Release (stream);
|
|
}
|
|
|
|
static void test_empty_image_2(void) {
|
|
LPBYTE data;
|
|
LPSTREAM stream;
|
|
IPicture* pic = NULL;
|
|
HRESULT hres;
|
|
LPVOID pvObj = NULL;
|
|
HGLOBAL hglob;
|
|
ULARGE_INTEGER newpos1;
|
|
LARGE_INTEGER seekto;
|
|
short type;
|
|
|
|
/* Empty image at random stream position. */
|
|
hglob = GlobalAlloc (0, 200);
|
|
data = GlobalLock (hglob);
|
|
data += 42;
|
|
memcpy(data,"lt\0\0",4);
|
|
((DWORD*)data)[1] = 0;
|
|
hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
|
|
ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08lx\n", hres);
|
|
|
|
memset(&seekto,0,sizeof(seekto));
|
|
seekto.u.LowPart = 42;
|
|
hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
|
|
ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);
|
|
|
|
pvObj = NULL;
|
|
hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
|
|
pic = pvObj;
|
|
ok(hres == S_OK,"empty picture not loaded, hres 0x%08lx\n", hres);
|
|
ok(pic != NULL,"empty picture not loaded, pic is NULL\n");
|
|
|
|
hres = IPicture_get_Type (pic, &type);
|
|
ok (hres == S_OK,"empty picture get type failed with hres 0x%08lx\n", hres);
|
|
ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);
|
|
|
|
IPicture_Release (pic);
|
|
IStream_Release (stream);
|
|
}
|
|
|
|
static void test_Invoke(void)
|
|
{
|
|
IPictureDisp *picdisp;
|
|
HRESULT hr;
|
|
VARIANTARG vararg, args[10];
|
|
DISPPARAMS dispparams;
|
|
VARIANT varresult;
|
|
IStream *stream;
|
|
HGLOBAL hglob;
|
|
void *data;
|
|
HDC hdc;
|
|
int i;
|
|
|
|
hglob = GlobalAlloc (0, sizeof(gifimage));
|
|
data = GlobalLock(hglob);
|
|
memcpy(data, gifimage, sizeof(gifimage));
|
|
GlobalUnlock(hglob);
|
|
|
|
hr = CreateStreamOnHGlobal (hglob, FALSE, &stream);
|
|
ok_ole_success(hr, "CreateStreamOnHGlobal");
|
|
|
|
hr = pOleLoadPicture(stream, sizeof(gifimage), TRUE, &IID_IPictureDisp, (void **)&picdisp);
|
|
IStream_Release(stream);
|
|
GlobalFree(hglob);
|
|
ok_ole_success(hr, "OleLoadPicture");
|
|
|
|
V_VT(&vararg) = VT_BOOL;
|
|
V_BOOL(&vararg) = VARIANT_FALSE;
|
|
dispparams.cNamedArgs = 0;
|
|
dispparams.rgdispidNamedArgs = NULL;
|
|
dispparams.cArgs = 1;
|
|
dispparams.rgvarg = &vararg;
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IPictureDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
|
|
ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08lx\n", hr);
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_IUnknown, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
|
|
ok(hr == DISP_E_UNKNOWNNAME, "IPictureDisp_Invoke should have returned DISP_E_UNKNOWNNAME instead of 0x%08lx\n", hr);
|
|
|
|
dispparams.cArgs = 0;
|
|
dispparams.rgvarg = NULL;
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
|
|
ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08lx\n", hr);
|
|
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYPUT, NULL, NULL, NULL, NULL);
|
|
ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08lx\n", hr);
|
|
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, NULL, NULL, NULL);
|
|
ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08lx\n", hr);
|
|
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
|
|
ok(hr == DISP_E_PARAMNOTOPTIONAL, "IPictureDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08lx\n", hr);
|
|
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
|
|
ok_ole_success(hr, "IPictureDisp_Invoke");
|
|
ok(V_VT(&varresult) == VT_I4, "V_VT(&varresult) should have been VT_UINT instead of %d\n", V_VT(&varresult));
|
|
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
|
|
ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08lx\n", hr);
|
|
|
|
hr = IPictureDisp_Invoke(picdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
|
|
ok(hr == DISP_E_MEMBERNOTFOUND, "IPictureDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08lx\n", hr);
|
|
|
|
dispparams.cArgs = 1;
|
|
dispparams.rgvarg = &vararg;
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
|
|
ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08lx\n", hr);
|
|
|
|
dispparams.cArgs = 1;
|
|
dispparams.rgvarg = &vararg;
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
|
|
ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08lx\n", hr);
|
|
|
|
/* DISPID_PICT_RENDER */
|
|
hdc = create_render_dc();
|
|
|
|
for (i = 0; i < ARRAY_SIZE(args); i++)
|
|
V_VT(&args[i]) = VT_I4;
|
|
|
|
V_I4(&args[0]) = 0;
|
|
V_I4(&args[1]) = 10;
|
|
V_I4(&args[2]) = 10;
|
|
V_I4(&args[3]) = 0;
|
|
V_I4(&args[4]) = 0;
|
|
V_I4(&args[5]) = 10;
|
|
V_I4(&args[6]) = 10;
|
|
V_I4(&args[7]) = 0;
|
|
V_I4(&args[8]) = 0;
|
|
V_I4(&args[9]) = HandleToLong(hdc);
|
|
|
|
dispparams.rgvarg = args;
|
|
dispparams.rgdispidNamedArgs = NULL;
|
|
dispparams.cArgs = 10;
|
|
dispparams.cNamedArgs = 0;
|
|
|
|
V_VT(&varresult) = VT_EMPTY;
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
|
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
|
|
|
/* Try with one argument set to VT_I2, it'd still work if coerced. */
|
|
V_VT(&args[3]) = VT_I2;
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
|
|
ok(hr == DISP_E_TYPEMISMATCH, "got 0x%08lx\n", hr);
|
|
V_VT(&args[3]) = VT_I4;
|
|
|
|
/* Wrong argument count */
|
|
dispparams.cArgs = 9;
|
|
hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
|
|
ok(hr == DISP_E_BADPARAMCOUNT, "got 0x%08lx\n", hr);
|
|
|
|
delete_render_dc(hdc);
|
|
IPictureDisp_Release(picdisp);
|
|
}
|
|
|
|
static HRESULT create_picture(short type, IPicture **pict)
|
|
{
|
|
PICTDESC desc;
|
|
|
|
desc.cbSizeofstruct = sizeof(desc);
|
|
desc.picType = type;
|
|
|
|
switch (type)
|
|
{
|
|
case PICTYPE_UNINITIALIZED:
|
|
return OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)pict);
|
|
|
|
case PICTYPE_NONE:
|
|
break;
|
|
|
|
case PICTYPE_BITMAP:
|
|
desc.u.bmp.hbitmap = CreateBitmap(1, 1, 1, 1, NULL);
|
|
desc.u.bmp.hpal = (HPALETTE)0xbeefdead;
|
|
break;
|
|
|
|
case PICTYPE_ICON:
|
|
desc.u.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
|
|
break;
|
|
|
|
case PICTYPE_METAFILE:
|
|
{
|
|
HDC hdc = CreateMetaFileA(NULL);
|
|
desc.u.wmf.hmeta = CloseMetaFile(hdc);
|
|
desc.u.wmf.xExt = 1;
|
|
desc.u.wmf.yExt = 1;
|
|
break;
|
|
}
|
|
|
|
case PICTYPE_ENHMETAFILE:
|
|
{
|
|
HDC hdc = CreateEnhMetaFileA(0, NULL, NULL, NULL);
|
|
desc.u.emf.hemf = CloseEnhMetaFile(hdc);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
ok(0, "picture type %d is not supported\n", type);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
return OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (void **)pict);
|
|
}
|
|
|
|
static void test_OleCreatePictureIndirect(void)
|
|
{
|
|
PICTDESC desc;
|
|
OLE_HANDLE handle;
|
|
IPicture *pict;
|
|
HRESULT hr;
|
|
short type, i;
|
|
|
|
if (0)
|
|
{
|
|
/* crashes on native */
|
|
OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, NULL);
|
|
}
|
|
|
|
desc.cbSizeofstruct = sizeof(desc);
|
|
desc.picType = PICTYPE_UNINITIALIZED;
|
|
pict = (void *)0xdeadbeef;
|
|
hr = OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (void **)&pict);
|
|
ok(hr == E_UNEXPECTED, "got %#lx\n", hr);
|
|
ok(pict == NULL, "got %p\n", pict);
|
|
|
|
for (i = PICTYPE_UNINITIALIZED; i <= PICTYPE_ENHMETAFILE; i++)
|
|
{
|
|
hr = create_picture(i, &pict);
|
|
ok(hr == S_OK, "%d: got %#lx\n", i, hr);
|
|
|
|
type = 0xdead;
|
|
hr = IPicture_get_Type(pict, &type);
|
|
ok(hr == S_OK, "%d: got %#lx\n", i, hr);
|
|
ok(type == i, "%d: got %d\n", i, type);
|
|
|
|
handle = 0xdeadbeef;
|
|
hr = IPicture_get_Handle(pict, &handle);
|
|
ok(hr == S_OK, "%d: got %#lx\n", i, hr);
|
|
if (type == PICTYPE_UNINITIALIZED || type == PICTYPE_NONE)
|
|
ok(handle == 0, "%d: got %#x\n", i, handle);
|
|
else
|
|
ok(handle != 0 && handle != 0xdeadbeef, "%d: got %#x\n", i, handle);
|
|
|
|
handle = 0xdeadbeef;
|
|
hr = IPicture_get_hPal(pict, &handle);
|
|
if (type == PICTYPE_BITMAP)
|
|
{
|
|
ok(hr == S_OK, "%d: got %#lx\n", i, hr);
|
|
ok(handle == 0xbeefdead, "%d: got %#x\n", i, handle);
|
|
}
|
|
else
|
|
{
|
|
ok(hr == E_FAIL, "%d: got %#lx\n", i, hr);
|
|
ok(handle == 0xdeadbeef || handle == 0 /* win64 */, "%d: got %#x\n", i, handle);
|
|
}
|
|
|
|
hr = IPicture_set_hPal(pict, HandleToUlong(GetStockObject(DEFAULT_PALETTE)));
|
|
if (type == PICTYPE_BITMAP)
|
|
ok(hr == S_OK, "%d: got %#lx\n", i, hr);
|
|
else
|
|
ok(hr == E_FAIL, "%d: got %#lx\n", i, hr);
|
|
|
|
IPicture_Release(pict);
|
|
}
|
|
}
|
|
|
|
static void test_apm(void)
|
|
{
|
|
OLE_HANDLE handle;
|
|
LPSTREAM stream;
|
|
IPicture *pict;
|
|
HGLOBAL hglob;
|
|
LPBYTE *data;
|
|
LONG cxy;
|
|
BOOL keep;
|
|
short type;
|
|
|
|
hglob = GlobalAlloc (0, sizeof(apmdata));
|
|
data = GlobalLock(hglob);
|
|
memcpy(data, apmdata, sizeof(apmdata));
|
|
|
|
ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
|
|
ole_check(pOleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
|
|
|
|
ole_check(IPicture_get_Handle(pict, &handle));
|
|
ok(handle != 0, "handle is null\n");
|
|
|
|
ole_check(IPicture_get_Type(pict, &type));
|
|
expect_eq(type, PICTYPE_METAFILE, short, "%d");
|
|
|
|
ole_check(IPicture_get_Height(pict, &cxy));
|
|
expect_eq(cxy, 1667l, LONG, "%ld");
|
|
|
|
ole_check(IPicture_get_Width(pict, &cxy));
|
|
expect_eq(cxy, 1323l, LONG, "%ld");
|
|
|
|
ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
|
|
todo_wine expect_eq(keep, (LONG)FALSE, LONG, "%ld");
|
|
|
|
ole_expect(IPicture_get_hPal(pict, &handle), E_FAIL);
|
|
IPicture_Release(pict);
|
|
IStream_Release(stream);
|
|
}
|
|
|
|
static void test_metafile(void)
|
|
{
|
|
LPSTREAM stream;
|
|
IPicture *pict;
|
|
HGLOBAL hglob;
|
|
LPBYTE *data;
|
|
|
|
hglob = GlobalAlloc (0, sizeof(metafile));
|
|
data = GlobalLock(hglob);
|
|
memcpy(data, metafile, sizeof(metafile));
|
|
|
|
ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
|
|
/* Windows does not load simple metafiles */
|
|
ole_expect(pOleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
|
|
|
|
IStream_Release(stream);
|
|
}
|
|
|
|
static void test_enhmetafile(void)
|
|
{
|
|
OLE_HANDLE handle;
|
|
LPSTREAM stream;
|
|
IPicture *pict;
|
|
HGLOBAL hglob;
|
|
LPBYTE *data;
|
|
LONG cxy;
|
|
BOOL keep;
|
|
short type;
|
|
|
|
hglob = GlobalAlloc (0, sizeof(enhmetafile));
|
|
data = GlobalLock(hglob);
|
|
memcpy(data, enhmetafile, sizeof(enhmetafile));
|
|
|
|
ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
|
|
ole_check(pOleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
|
|
|
|
ole_check(IPicture_get_Handle(pict, &handle));
|
|
ok(handle != 0, "handle is null\n");
|
|
|
|
ole_check(IPicture_get_Type(pict, &type));
|
|
expect_eq(type, PICTYPE_ENHMETAFILE, short, "%d");
|
|
|
|
ole_check(IPicture_get_Height(pict, &cxy));
|
|
expect_eq(cxy, -23l, LONG, "%ld");
|
|
|
|
ole_check(IPicture_get_Width(pict, &cxy));
|
|
expect_eq(cxy, -25l, LONG, "%ld");
|
|
|
|
ole_check(IPicture_get_KeepOriginalFormat(pict, &keep));
|
|
todo_wine expect_eq(keep, (LONG)FALSE, LONG, "%ld");
|
|
|
|
IPicture_Release(pict);
|
|
IStream_Release(stream);
|
|
}
|
|
|
|
static HRESULT picture_render(IPicture *iface, HDC hdc, LONG x, LONG y, LONG cx, LONG cy,
|
|
OLE_XPOS_HIMETRIC xSrc,
|
|
OLE_YPOS_HIMETRIC ySrc,
|
|
OLE_XSIZE_HIMETRIC cxSrc,
|
|
OLE_YSIZE_HIMETRIC cySrc,
|
|
const RECT *bounds)
|
|
{
|
|
VARIANT ret, args[10];
|
|
HRESULT hr, hr_disp;
|
|
DISPPARAMS params;
|
|
IDispatch *disp;
|
|
int i;
|
|
|
|
hr = IPicture_Render(iface, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, bounds);
|
|
|
|
IPicture_QueryInterface(iface, &IID_IDispatch, (void**)&disp);
|
|
|
|
/* This is broken on 64 bits - accepted pointer argument type is still VT_I4 */
|
|
for (i = 0; i < ARRAY_SIZE(args); i++)
|
|
V_VT(&args[i]) = VT_I4;
|
|
|
|
/* pack arguments and call */
|
|
V_INT_PTR(&args[0]) = (INT_PTR)bounds;
|
|
V_I4(&args[1]) = cySrc;
|
|
V_I4(&args[2]) = cxSrc;
|
|
V_I4(&args[3]) = ySrc;
|
|
V_I4(&args[4]) = xSrc;
|
|
V_I4(&args[5]) = cy;
|
|
V_I4(&args[6]) = cx;
|
|
V_I4(&args[7]) = y;
|
|
V_I4(&args[8]) = x;
|
|
V_I4(&args[9]) = HandleToLong(hdc);
|
|
|
|
params.rgvarg = args;
|
|
params.rgdispidNamedArgs = NULL;
|
|
params.cArgs = 10;
|
|
params.cNamedArgs = 0;
|
|
|
|
V_VT(&ret) = VT_EMPTY;
|
|
hr_disp = IDispatch_Invoke(disp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD,
|
|
¶ms, &ret, NULL, NULL);
|
|
ok(hr == hr_disp, "DISPID_PICT_RENDER returned wrong code, 0x%08lx, expected 0x%08lx\n",
|
|
hr_disp, hr);
|
|
|
|
IDispatch_Release(disp);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static void test_Render(void)
|
|
{
|
|
IPicture *pic;
|
|
HRESULT hres;
|
|
short type;
|
|
PICTDESC desc;
|
|
OLE_XSIZE_HIMETRIC pWidth;
|
|
OLE_YSIZE_HIMETRIC pHeight;
|
|
COLORREF result, expected;
|
|
HDC hdc = create_render_dc();
|
|
|
|
/* test IPicture::Render return code on uninitialized picture */
|
|
hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
|
|
ok(hres == S_OK, "Failed to create a picture, hr %#lx.\n", hres);
|
|
hres = IPicture_get_Type(pic, &type);
|
|
ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08lx\n", hres);
|
|
ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
|
|
/* zero dimensions */
|
|
hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
/* nonzero dimensions, PICTYPE_UNINITIALIZED */
|
|
hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL);
|
|
ole_expect(hres, S_OK);
|
|
IPicture_Release(pic);
|
|
|
|
desc.cbSizeofstruct = sizeof(PICTDESC);
|
|
desc.picType = PICTYPE_ICON;
|
|
desc.u.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
|
|
if(!desc.u.icon.hicon){
|
|
win_skip("LoadIcon failed. Skipping...\n");
|
|
delete_render_dc(hdc);
|
|
return;
|
|
}
|
|
|
|
hres = OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (void **)&pic);
|
|
ok(hres == S_OK, "Failed to create a picture, hr %#lx.\n", hres);
|
|
/* zero dimensions, PICTYPE_ICON */
|
|
hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL);
|
|
ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE);
|
|
|
|
/* Check if target size and position is respected */
|
|
IPicture_get_Width(pic, &pWidth);
|
|
IPicture_get_Height(pic, &pHeight);
|
|
|
|
SetPixelV(hdc, 0, 0, 0x00223344);
|
|
SetPixelV(hdc, 5, 5, 0x00223344);
|
|
SetPixelV(hdc, 10, 10, 0x00223344);
|
|
expected = GetPixel(hdc, 0, 0);
|
|
|
|
hres = picture_render(pic, hdc, 1, 1, 9, 9, 0, pHeight, pWidth, -pHeight, NULL);
|
|
ole_expect(hres, S_OK);
|
|
|
|
if(hres != S_OK) goto done;
|
|
|
|
/* Evaluate the rendered Icon */
|
|
result = GetPixel(hdc, 0, 0);
|
|
ok(result == expected,
|
|
"Color at 0,0 should be unchanged 0x%06lX, but was 0x%06lX\n", expected, result);
|
|
result = GetPixel(hdc, 5, 5);
|
|
ok(result != expected,
|
|
"Color at 5,5 should have changed, but still was 0x%06lX\n", expected);
|
|
result = GetPixel(hdc, 10, 10);
|
|
ok(result == expected,
|
|
"Color at 10,10 should be unchanged 0x%06lX, but was 0x%06lX\n", expected, result);
|
|
|
|
done:
|
|
IPicture_Release(pic);
|
|
delete_render_dc(hdc);
|
|
}
|
|
|
|
static void test_get_Attributes(void)
|
|
{
|
|
IPicture *pic;
|
|
HRESULT hres;
|
|
short type;
|
|
DWORD attr;
|
|
|
|
hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
|
|
ok(hres == S_OK, "Failed to create a picture, hr %#lx.\n", hres);
|
|
hres = IPicture_get_Type(pic, &type);
|
|
ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08lx\n", hres);
|
|
ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type);
|
|
|
|
hres = IPicture_get_Attributes(pic, NULL);
|
|
ole_expect(hres, E_POINTER);
|
|
|
|
attr = 0xdeadbeef;
|
|
hres = IPicture_get_Attributes(pic, &attr);
|
|
ole_expect(hres, S_OK);
|
|
ok(attr == 0, "IPicture_get_Attributes does not reset attr to zero, got %ld\n", attr);
|
|
|
|
IPicture_Release(pic);
|
|
}
|
|
|
|
static void test_get_Handle(void)
|
|
{
|
|
IPicture *pic;
|
|
HRESULT hres;
|
|
|
|
hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
|
|
ok(hres == S_OK, "Failed to create a picture, hr %#lx.\n", hres);
|
|
hres = IPicture_get_Handle(pic, NULL);
|
|
ole_expect(hres, E_POINTER);
|
|
|
|
IPicture_Release(pic);
|
|
}
|
|
|
|
static void test_get_Type(void)
|
|
{
|
|
IPicture *pic;
|
|
HRESULT hres;
|
|
|
|
hres = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void **)&pic);
|
|
ok(hres == S_OK, "Failed to create a picture, hr %#lx.\n", hres);
|
|
|
|
hres = IPicture_get_Type(pic, NULL);
|
|
ole_expect(hres, E_POINTER);
|
|
|
|
IPicture_Release(pic);
|
|
}
|
|
|
|
static void test_OleLoadPicturePath(void)
|
|
{
|
|
static WCHAR emptyW[] = {0};
|
|
|
|
IPicture *pic;
|
|
HRESULT hres;
|
|
int i;
|
|
char temp_path[MAX_PATH];
|
|
char temp_file[MAX_PATH];
|
|
WCHAR temp_fileW[MAX_PATH + 5] = {'f','i','l','e',':','/','/','/'};
|
|
HANDLE file;
|
|
DWORD size;
|
|
WCHAR *ptr;
|
|
|
|
const struct
|
|
{
|
|
LPOLESTR szURLorPath;
|
|
REFIID riid;
|
|
IPicture **pic;
|
|
} invalid_parameters[] =
|
|
{
|
|
{NULL, NULL, NULL},
|
|
{NULL, NULL, &pic},
|
|
{NULL, &IID_IPicture, NULL},
|
|
{NULL, &IID_IPicture, &pic},
|
|
{emptyW, NULL, NULL},
|
|
{emptyW, &IID_IPicture, NULL},
|
|
};
|
|
|
|
for (i = 0; i < ARRAY_SIZE(invalid_parameters); i++)
|
|
{
|
|
pic = (IPicture *)0xdeadbeef;
|
|
hres = OleLoadPicturePath(invalid_parameters[i].szURLorPath, NULL, 0, 0,
|
|
invalid_parameters[i].riid,
|
|
(void **)invalid_parameters[i].pic);
|
|
ok(hres == E_INVALIDARG,
|
|
"[%d] Expected OleLoadPicturePath to return E_INVALIDARG, got 0x%08lx\n", i, hres);
|
|
ok(pic == (IPicture *)0xdeadbeef,
|
|
"[%d] Expected output pointer to be 0xdeadbeef, got %p\n", i, pic);
|
|
}
|
|
|
|
pic = (IPicture *)0xdeadbeef;
|
|
hres = OleLoadPicturePath(emptyW, NULL, 0, 0, NULL, (void **)&pic);
|
|
todo_wine
|
|
ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
|
|
broken(hres == E_UNEXPECTED) || /* NT4 */
|
|
broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
|
|
"Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08lx\n", hres);
|
|
ok(pic == NULL,
|
|
"Expected the output interface pointer to be NULL, got %p\n", pic);
|
|
|
|
pic = (IPicture *)0xdeadbeef;
|
|
hres = OleLoadPicturePath(emptyW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
|
|
todo_wine
|
|
ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
|
|
broken(hres == E_UNEXPECTED) || /* NT4 */
|
|
broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
|
|
"Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08lx\n", hres);
|
|
ok(pic == NULL,
|
|
"Expected the output interface pointer to be NULL, got %p\n", pic);
|
|
|
|
/* Create a local temporary image file for testing. */
|
|
GetTempPathA(sizeof(temp_path), temp_path);
|
|
GetTempFileNameA(temp_path, "bmp", 0, temp_file);
|
|
file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
|
|
CloseHandle(file);
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, temp_file, -1, temp_fileW + 8, ARRAY_SIZE(temp_fileW) - 8);
|
|
|
|
/* Try a normal DOS path. */
|
|
hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
|
|
ok(hres == S_OK ||
|
|
broken(hres == E_UNEXPECTED), /* NT4 */
|
|
"Expected OleLoadPicturePath to return S_OK, got 0x%08lx\n", hres);
|
|
if (pic)
|
|
IPicture_Release(pic);
|
|
|
|
/* Try a DOS path with tacked on "file:". */
|
|
hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
|
|
ok(hres == S_OK ||
|
|
broken(hres == E_UNEXPECTED), /* NT4 */
|
|
"Expected OleLoadPicturePath to return S_OK, got 0x%08lx\n", hres);
|
|
if (pic)
|
|
IPicture_Release(pic);
|
|
|
|
DeleteFileA(temp_file);
|
|
|
|
/* Try with a nonexistent file. */
|
|
hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
|
|
ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
|
|
broken(hres == E_UNEXPECTED) || /* NT4 */
|
|
broken(hres == E_FAIL), /*Win2k */
|
|
"Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08lx\n", hres);
|
|
|
|
hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
|
|
ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
|
|
broken(hres == E_UNEXPECTED) || /* NT4 */
|
|
broken(hres == E_FAIL), /* Win2k */
|
|
"Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08lx\n", hres);
|
|
|
|
file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
WriteFile(file, bmpimage, sizeof(bmpimage), &size, NULL);
|
|
CloseHandle(file);
|
|
|
|
/* Try a "file:" URL with slash separators. */
|
|
ptr = temp_fileW + 8;
|
|
while (*ptr)
|
|
{
|
|
if (*ptr == '\\')
|
|
*ptr = '/';
|
|
ptr++;
|
|
}
|
|
|
|
hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
|
|
ok(hres == S_OK ||
|
|
broken(hres == E_UNEXPECTED), /* NT4 */
|
|
"Expected OleLoadPicturePath to return S_OK, got 0x%08lx\n", hres);
|
|
if (pic)
|
|
IPicture_Release(pic);
|
|
|
|
DeleteFileA(temp_file);
|
|
|
|
/* Try with a nonexistent file. */
|
|
hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
|
|
ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
|
|
broken(hres == E_UNEXPECTED) || /* NT4 */
|
|
broken(hres == E_FAIL), /* Win2k */
|
|
"Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08lx\n", hres);
|
|
}
|
|
|
|
static void test_himetric(void)
|
|
{
|
|
static const BYTE bmp_bits[1024];
|
|
OLE_XSIZE_HIMETRIC cx;
|
|
OLE_YSIZE_HIMETRIC cy;
|
|
IPicture *pic;
|
|
PICTDESC desc;
|
|
HBITMAP bmp;
|
|
HRESULT hr;
|
|
HICON icon;
|
|
HDC hdc;
|
|
INT d;
|
|
|
|
desc.cbSizeofstruct = sizeof(desc);
|
|
desc.picType = PICTYPE_BITMAP;
|
|
desc.u.bmp.hpal = NULL;
|
|
|
|
hdc = CreateCompatibleDC(0);
|
|
|
|
bmp = CreateBitmap(1.9 * GetDeviceCaps(hdc, LOGPIXELSX),
|
|
1.9 * GetDeviceCaps(hdc, LOGPIXELSY), 1, 1, NULL);
|
|
|
|
desc.u.bmp.hbitmap = bmp;
|
|
|
|
/* size in himetric units reported rounded up to next integer value */
|
|
hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
|
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
|
|
|
cx = 0;
|
|
d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSX)), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
|
|
hr = IPicture_get_Width(pic, &cx);
|
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
|
ok(cx == d, "got %ld, expected %d\n", cx, d);
|
|
|
|
cy = 0;
|
|
d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSY)), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
|
|
hr = IPicture_get_Height(pic, &cy);
|
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
|
ok(cy == d, "got %ld, expected %d\n", cy, d);
|
|
|
|
DeleteObject(bmp);
|
|
IPicture_Release(pic);
|
|
|
|
/* same thing with icon */
|
|
icon = CreateIcon(NULL, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
|
|
1, 1, bmp_bits, bmp_bits);
|
|
ok(icon != NULL, "failed to create icon\n");
|
|
|
|
desc.picType = PICTYPE_ICON;
|
|
desc.u.icon.hicon = icon;
|
|
|
|
hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
|
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
|
|
|
cx = 0;
|
|
d = MulDiv(GetSystemMetrics(SM_CXICON), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
|
|
hr = IPicture_get_Width(pic, &cx);
|
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
|
ok(cx == d, "got %ld, expected %d\n", cx, d);
|
|
|
|
cy = 0;
|
|
d = MulDiv(GetSystemMetrics(SM_CYICON), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
|
|
hr = IPicture_get_Height(pic, &cy);
|
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
|
ok(cy == d, "got %ld, expected %d\n", cy, d);
|
|
|
|
IPicture_Release(pic);
|
|
DestroyIcon(icon);
|
|
|
|
DeleteDC(hdc);
|
|
}
|
|
|
|
static void test_load_save_bmp(void)
|
|
{
|
|
IPicture *pic;
|
|
PICTDESC desc;
|
|
short type;
|
|
OLE_HANDLE handle;
|
|
HGLOBAL hmem;
|
|
DWORD *mem;
|
|
IPersistStream *src_stream;
|
|
IStream *dst_stream;
|
|
LARGE_INTEGER offset;
|
|
HRESULT hr;
|
|
LONG size;
|
|
|
|
desc.cbSizeofstruct = sizeof(desc);
|
|
desc.picType = PICTYPE_BITMAP;
|
|
desc.u.bmp.hpal = 0;
|
|
desc.u.bmp.hbitmap = CreateBitmap(1, 1, 1, 1, NULL);
|
|
hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
|
|
ok(hr == S_OK, "OleCreatePictureIndirect error %#lx\n", hr);
|
|
|
|
type = -1;
|
|
hr = IPicture_get_Type(pic, &type);
|
|
ok(hr == S_OK,"get_Type error %#8lx\n", hr);
|
|
ok(type == PICTYPE_BITMAP,"expected picture type PICTYPE_BITMAP, got %d\n", type);
|
|
|
|
hr = IPicture_get_Handle(pic, &handle);
|
|
ok(hr == S_OK,"get_Handle error %#8lx\n", hr);
|
|
ok(IntToPtr(handle) == desc.u.bmp.hbitmap, "get_Handle returned wrong handle %#x\n", handle);
|
|
|
|
hmem = GlobalAlloc(GMEM_ZEROINIT, 4096);
|
|
hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
|
|
ok(hr == S_OK, "createstreamonhglobal error %#lx\n", hr);
|
|
|
|
size = -1;
|
|
hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
|
|
ok(hr == S_OK, "IPicture_SaveasFile error %#lx\n", hr);
|
|
todo_wine
|
|
ok(size == 66, "expected 66, got %ld\n", size);
|
|
mem = GlobalLock(hmem);
|
|
todo_wine
|
|
ok(!memcmp(&mem[0], "BM", 2), "got wrong bmp header %04lx\n", mem[0]);
|
|
GlobalUnlock(hmem);
|
|
|
|
size = -1;
|
|
hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
|
|
todo_wine
|
|
ok(hr == E_FAIL, "expected E_FAIL, got %#lx\n", hr);
|
|
todo_wine
|
|
ok(size == -1, "expected -1, got %ld\n", size);
|
|
|
|
offset.QuadPart = 0;
|
|
hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
|
|
ok(hr == S_OK, "IStream_Seek %#lx\n", hr);
|
|
|
|
hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
|
|
ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
|
|
|
|
hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
|
|
ok(hr == S_OK, "Save error %#lx\n", hr);
|
|
|
|
IPersistStream_Release(src_stream);
|
|
IStream_Release(dst_stream);
|
|
|
|
mem = GlobalLock(hmem);
|
|
ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04lx\n", mem[0]);
|
|
ok(mem[1] == 66, "expected stream size 66, got %lu\n", mem[1]);
|
|
ok(!memcmp(&mem[2], "BM", 2), "got wrong bmp header %04lx\n", mem[2]);
|
|
|
|
GlobalUnlock(hmem);
|
|
GlobalFree(hmem);
|
|
|
|
DeleteObject(desc.u.bmp.hbitmap);
|
|
IPicture_Release(pic);
|
|
}
|
|
|
|
static void test_load_save_icon(void)
|
|
{
|
|
IPicture *pic;
|
|
PICTDESC desc;
|
|
short type;
|
|
OLE_HANDLE handle;
|
|
HGLOBAL hmem;
|
|
DWORD *mem;
|
|
IPersistStream *src_stream;
|
|
IStream *dst_stream;
|
|
LARGE_INTEGER offset;
|
|
HRESULT hr;
|
|
LONG size;
|
|
|
|
desc.cbSizeofstruct = sizeof(desc);
|
|
desc.picType = PICTYPE_ICON;
|
|
desc.u.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION);
|
|
hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
|
|
ok(hr == S_OK, "OleCreatePictureIndirect error %#lx\n", hr);
|
|
|
|
type = -1;
|
|
hr = IPicture_get_Type(pic, &type);
|
|
ok(hr == S_OK,"get_Type error %#8lx\n", hr);
|
|
ok(type == PICTYPE_ICON,"expected picture type PICTYPE_ICON, got %d\n", type);
|
|
|
|
hr = IPicture_get_Handle(pic, &handle);
|
|
ok(hr == S_OK,"get_Handle error %#8lx\n", hr);
|
|
ok(IntToPtr(handle) == desc.u.icon.hicon, "get_Handle returned wrong handle %#x\n", handle);
|
|
|
|
hmem = GlobalAlloc(GMEM_ZEROINIT, 8192);
|
|
hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
|
|
ok(hr == S_OK, "CreateStreamOnHGlobal error %#lx\n", hr);
|
|
|
|
size = -1;
|
|
hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
|
|
ok(hr == S_OK, "IPicture_SaveasFile error %#lx\n", hr);
|
|
todo_wine
|
|
ok(size == 766, "expected 766, got %ld\n", size);
|
|
mem = GlobalLock(hmem);
|
|
todo_wine
|
|
ok(mem[0] == 0x00010000, "got wrong icon header %04lx\n", mem[0]);
|
|
GlobalUnlock(hmem);
|
|
|
|
size = -1;
|
|
hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
|
|
todo_wine
|
|
ok(hr == E_FAIL, "expected E_FAIL, got %#lx\n", hr);
|
|
todo_wine
|
|
ok(size == -1, "expected -1, got %ld\n", size);
|
|
|
|
offset.QuadPart = 0;
|
|
hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
|
|
ok(hr == S_OK, "IStream_Seek %#lx\n", hr);
|
|
|
|
hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
|
|
ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
|
|
|
|
hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
|
|
ok(hr == S_OK, "Saveerror %#lx\n", hr);
|
|
|
|
IPersistStream_Release(src_stream);
|
|
IStream_Release(dst_stream);
|
|
|
|
mem = GlobalLock(hmem);
|
|
ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04lx\n", mem[0]);
|
|
todo_wine
|
|
ok(mem[1] == 766, "expected stream size 766, got %lu\n", mem[1]);
|
|
ok(mem[2] == 0x00010000, "got wrong icon header %04lx\n", mem[2]);
|
|
|
|
GlobalUnlock(hmem);
|
|
GlobalFree(hmem);
|
|
|
|
DestroyIcon(desc.u.icon.hicon);
|
|
IPicture_Release(pic);
|
|
}
|
|
|
|
static void test_load_save_empty_picture(void)
|
|
{
|
|
IPicture *pic;
|
|
PICTDESC desc;
|
|
short type;
|
|
OLE_HANDLE handle;
|
|
HGLOBAL hmem;
|
|
DWORD *mem;
|
|
IPersistStream *src_stream;
|
|
IStream *dst_stream, *stream;
|
|
LARGE_INTEGER offset;
|
|
HRESULT hr;
|
|
LONG size;
|
|
|
|
memset(&pic, 0, sizeof(pic));
|
|
desc.cbSizeofstruct = sizeof(desc);
|
|
desc.picType = PICTYPE_NONE;
|
|
hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void **)&pic);
|
|
ok(hr == S_OK, "OleCreatePictureIndirect error %#lx\n", hr);
|
|
|
|
type = -1;
|
|
hr = IPicture_get_Type(pic, &type);
|
|
ok(hr == S_OK, "get_Type error %#lx\n", hr);
|
|
ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
|
|
|
|
handle = (OLE_HANDLE)0xdeadbeef;
|
|
hr = IPicture_get_Handle(pic, &handle);
|
|
ok(hr == S_OK,"get_Handle error %#8lx\n", hr);
|
|
ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
|
|
|
|
hmem = GlobalAlloc(GMEM_ZEROINIT, 4096);
|
|
hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
|
|
ok(hr == S_OK, "createstreamonhglobal error %#lx\n", hr);
|
|
|
|
size = -1;
|
|
hr = IPicture_SaveAsFile(pic, dst_stream, TRUE, &size);
|
|
ok(hr == S_OK, "IPicture_SaveasFile error %#lx\n", hr);
|
|
todo_wine
|
|
ok(size == -1, "expected -1, got %ld\n", size);
|
|
|
|
size = -1;
|
|
hr = IPicture_SaveAsFile(pic, dst_stream, FALSE, &size);
|
|
ok(hr == S_OK, "IPicture_SaveasFile error %#lx\n", hr);
|
|
todo_wine
|
|
ok(size == -1, "expected -1, got %ld\n", size);
|
|
|
|
hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
|
|
ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
|
|
|
|
hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
|
|
ok(hr == S_OK, "Save error %#lx\n", hr);
|
|
|
|
mem = GlobalLock(hmem);
|
|
ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04lx\n", mem[0]);
|
|
ok(mem[1] == 0, "expected stream size 0, got %lu\n", mem[1]);
|
|
GlobalUnlock(hmem);
|
|
|
|
IPersistStream_Release(src_stream);
|
|
IPicture_Release(pic);
|
|
|
|
/* first with statable and seekable stream */
|
|
offset.QuadPart = 0;
|
|
hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL);
|
|
ok(hr == S_OK, "IStream_Seek %#lx\n", hr);
|
|
|
|
pic = NULL;
|
|
hr = pOleLoadPicture(dst_stream, 0, FALSE, &IID_IPicture, (void **)&pic);
|
|
ok(hr == S_OK, "OleLoadPicture error %#lx\n", hr);
|
|
ok(pic != NULL,"picture should not be not NULL\n");
|
|
if (pic != NULL)
|
|
{
|
|
type = -1;
|
|
hr = IPicture_get_Type(pic, &type);
|
|
ok(hr == S_OK,"get_Type error %#8lx\n", hr);
|
|
ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
|
|
|
|
handle = (OLE_HANDLE)0xdeadbeef;
|
|
hr = IPicture_get_Handle(pic, &handle);
|
|
ok(hr == S_OK,"get_Handle error %#8lx\n", hr);
|
|
ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
|
|
|
|
IPicture_Release(pic);
|
|
}
|
|
IStream_Release(dst_stream);
|
|
|
|
/* again with non-statable and non-seekable stream */
|
|
stream = NoStatStream_Construct(hmem);
|
|
ok(stream != NULL, "failed to create empty image stream\n");
|
|
|
|
pic = NULL;
|
|
hr = pOleLoadPicture(stream, 0, FALSE, &IID_IPicture, (void **)&pic);
|
|
ok(hr == S_OK, "OleLoadPicture error %#lx\n", hr);
|
|
ok(pic != NULL,"picture should not be not NULL\n");
|
|
if (pic != NULL)
|
|
{
|
|
type = -1;
|
|
hr = IPicture_get_Type(pic, &type);
|
|
ok(hr == S_OK,"get_Type error %#8lx\n", hr);
|
|
ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
|
|
|
|
handle = (OLE_HANDLE)0xdeadbeef;
|
|
hr = IPicture_get_Handle(pic, &handle);
|
|
ok(hr == S_OK,"get_Handle error %#8lx\n", hr);
|
|
ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
|
|
|
|
IPicture_Release(pic);
|
|
}
|
|
/* Non-statable impl always deletes on release */
|
|
IStream_Release(stream);
|
|
}
|
|
|
|
START_TEST(olepicture)
|
|
{
|
|
hOleaut32 = GetModuleHandleA("oleaut32.dll");
|
|
pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
|
|
pOleLoadPictureEx = (void*)GetProcAddress(hOleaut32, "OleLoadPictureEx");
|
|
if (!pOleLoadPicture)
|
|
{
|
|
win_skip("OleLoadPicture is not available\n");
|
|
return;
|
|
}
|
|
|
|
/* Test regular 1x1 pixel images of gif, jpg, bmp type */
|
|
test_pic(gifimage, sizeof(gifimage));
|
|
test_pic(jpgimage, sizeof(jpgimage));
|
|
test_pic(bmpimage, sizeof(bmpimage));
|
|
test_pic(gif4pixel, sizeof(gif4pixel));
|
|
/* FIXME: No PNG support in Windows... */
|
|
if (0) test_pic(pngimage, sizeof(pngimage));
|
|
test_empty_image();
|
|
test_empty_image_2();
|
|
if (pOleLoadPictureEx)
|
|
{
|
|
test_apm();
|
|
test_metafile();
|
|
test_enhmetafile();
|
|
}
|
|
else
|
|
win_skip("OleLoadPictureEx is not available\n");
|
|
test_Invoke();
|
|
test_OleCreatePictureIndirect();
|
|
test_Render();
|
|
test_get_Attributes();
|
|
test_get_Handle();
|
|
test_get_Type();
|
|
test_OleLoadPicturePath();
|
|
test_himetric();
|
|
test_load_save_bmp();
|
|
test_load_save_icon();
|
|
test_load_save_empty_picture();
|
|
}
|
|
|
|
|
|
/* Helper functions only ... */
|
|
|
|
|
|
static inline NoStatStreamImpl *impl_from_IStream(IStream *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, NoStatStreamImpl, IStream_iface);
|
|
}
|
|
|
|
static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
|
|
{
|
|
GlobalFree(This->supportHandle);
|
|
This->supportHandle=0;
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
|
|
static ULONG WINAPI NoStatStreamImpl_AddRef(
|
|
IStream* iface)
|
|
{
|
|
NoStatStreamImpl* const This = impl_from_IStream(iface);
|
|
return InterlockedIncrement(&This->ref);
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
|
|
IStream* iface,
|
|
REFIID riid, /* [in] */
|
|
void** ppvObject) /* [iid_is][out] */
|
|
{
|
|
NoStatStreamImpl* const This = impl_from_IStream(iface);
|
|
if (ppvObject==0) return E_INVALIDARG;
|
|
*ppvObject = 0;
|
|
|
|
if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IStream, riid))
|
|
*ppvObject = &This->IStream_iface;
|
|
|
|
if ((*ppvObject)==0)
|
|
return E_NOINTERFACE;
|
|
NoStatStreamImpl_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
static ULONG WINAPI NoStatStreamImpl_Release(
|
|
IStream* iface)
|
|
{
|
|
NoStatStreamImpl* const This = impl_from_IStream(iface);
|
|
ULONG newRef = InterlockedDecrement(&This->ref);
|
|
if (newRef==0)
|
|
NoStatStreamImpl_Destroy(This);
|
|
return newRef;
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_Read(
|
|
IStream* iface,
|
|
void* pv, /* [length_is][size_is][out] */
|
|
ULONG cb, /* [in] */
|
|
ULONG* pcbRead) /* [out] */
|
|
{
|
|
NoStatStreamImpl* const This = impl_from_IStream(iface);
|
|
void* supportBuffer;
|
|
ULONG bytesReadBuffer;
|
|
ULONG bytesToReadFromBuffer;
|
|
|
|
if (pcbRead==0)
|
|
pcbRead = &bytesReadBuffer;
|
|
bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
|
|
supportBuffer = GlobalLock(This->supportHandle);
|
|
memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
|
|
This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
|
|
*pcbRead = bytesToReadFromBuffer;
|
|
GlobalUnlock(This->supportHandle);
|
|
if(*pcbRead == cb)
|
|
return S_OK;
|
|
return S_FALSE;
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_Write(
|
|
IStream* iface,
|
|
const void* pv, /* [size_is][in] */
|
|
ULONG cb, /* [in] */
|
|
ULONG* pcbWritten) /* [out] */
|
|
{
|
|
NoStatStreamImpl* const This = impl_from_IStream(iface);
|
|
void* supportBuffer;
|
|
ULARGE_INTEGER newSize;
|
|
ULONG bytesWritten = 0;
|
|
|
|
if (pcbWritten == 0)
|
|
pcbWritten = &bytesWritten;
|
|
if (cb == 0)
|
|
return S_OK;
|
|
newSize.u.HighPart = 0;
|
|
newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
|
|
if (newSize.u.LowPart > This->streamSize.u.LowPart)
|
|
IStream_SetSize(iface, newSize);
|
|
|
|
supportBuffer = GlobalLock(This->supportHandle);
|
|
memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
|
|
This->currentPosition.u.LowPart+=cb;
|
|
*pcbWritten = cb;
|
|
GlobalUnlock(This->supportHandle);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_Seek(
|
|
IStream* iface,
|
|
LARGE_INTEGER dlibMove, /* [in] */
|
|
DWORD dwOrigin, /* [in] */
|
|
ULARGE_INTEGER* plibNewPosition) /* [out] */
|
|
{
|
|
NoStatStreamImpl* const This = impl_from_IStream(iface);
|
|
ULARGE_INTEGER newPosition;
|
|
switch (dwOrigin)
|
|
{
|
|
case STREAM_SEEK_SET:
|
|
newPosition.u.HighPart = 0;
|
|
newPosition.u.LowPart = 0;
|
|
break;
|
|
case STREAM_SEEK_CUR:
|
|
newPosition = This->currentPosition;
|
|
break;
|
|
case STREAM_SEEK_END:
|
|
newPosition = This->streamSize;
|
|
break;
|
|
default:
|
|
return STG_E_INVALIDFUNCTION;
|
|
}
|
|
if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart)
|
|
return STG_E_INVALIDFUNCTION;
|
|
newPosition.QuadPart += dlibMove.QuadPart;
|
|
if (plibNewPosition) *plibNewPosition = newPosition;
|
|
This->currentPosition = newPosition;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_SetSize(
|
|
IStream* iface,
|
|
ULARGE_INTEGER libNewSize) /* [in] */
|
|
{
|
|
NoStatStreamImpl* const This = impl_from_IStream(iface);
|
|
HGLOBAL supportHandle;
|
|
if (libNewSize.u.HighPart != 0)
|
|
return STG_E_INVALIDFUNCTION;
|
|
if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
|
|
return S_OK;
|
|
supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
|
|
if (supportHandle == 0)
|
|
return STG_E_MEDIUMFULL;
|
|
This->supportHandle = supportHandle;
|
|
This->streamSize.u.LowPart = libNewSize.u.LowPart;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_CopyTo(
|
|
IStream* iface,
|
|
IStream* pstm, /* [unique][in] */
|
|
ULARGE_INTEGER cb, /* [in] */
|
|
ULARGE_INTEGER* pcbRead, /* [out] */
|
|
ULARGE_INTEGER* pcbWritten) /* [out] */
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BYTE tmpBuffer[128];
|
|
ULONG bytesRead, bytesWritten, copySize;
|
|
ULARGE_INTEGER totalBytesRead;
|
|
ULARGE_INTEGER totalBytesWritten;
|
|
|
|
if ( pstm == 0 )
|
|
return STG_E_INVALIDPOINTER;
|
|
totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0;
|
|
totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0;
|
|
|
|
while ( cb.u.LowPart > 0 )
|
|
{
|
|
if ( cb.u.LowPart >= 128 )
|
|
copySize = 128;
|
|
else
|
|
copySize = cb.u.LowPart;
|
|
IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
|
|
totalBytesRead.u.LowPart += bytesRead;
|
|
IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
|
|
totalBytesWritten.u.LowPart += bytesWritten;
|
|
if (bytesRead != bytesWritten)
|
|
{
|
|
hr = STG_E_MEDIUMFULL;
|
|
break;
|
|
}
|
|
if (bytesRead!=copySize)
|
|
cb.u.LowPart = 0;
|
|
else
|
|
cb.u.LowPart -= bytesRead;
|
|
}
|
|
if (pcbRead)
|
|
{
|
|
pcbRead->u.LowPart = totalBytesRead.u.LowPart;
|
|
pcbRead->u.HighPart = totalBytesRead.u.HighPart;
|
|
}
|
|
|
|
if (pcbWritten)
|
|
{
|
|
pcbWritten->u.LowPart = totalBytesWritten.u.LowPart;
|
|
pcbWritten->u.HighPart = totalBytesWritten.u.HighPart;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_Commit(IStream* iface,DWORD grfCommitFlags)
|
|
{
|
|
return S_OK;
|
|
}
|
|
static HRESULT WINAPI NoStatStreamImpl_Revert(IStream* iface) { return S_OK; }
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_LockRegion(
|
|
IStream* iface,
|
|
ULARGE_INTEGER libOffset, /* [in] */
|
|
ULARGE_INTEGER cb, /* [in] */
|
|
DWORD dwLockType) /* [in] */
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_UnlockRegion(
|
|
IStream* iface,
|
|
ULARGE_INTEGER libOffset, /* [in] */
|
|
ULARGE_INTEGER cb, /* [in] */
|
|
DWORD dwLockType) /* [in] */
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_Stat(
|
|
IStream* iface,
|
|
STATSTG* pstatstg, /* [out] */
|
|
DWORD grfStatFlag) /* [in] */
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI NoStatStreamImpl_Clone(
|
|
IStream* iface,
|
|
IStream** ppstm) /* [out] */
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
static const IStreamVtbl NoStatStreamImpl_Vtbl;
|
|
|
|
/*
|
|
Build an object that implements IStream, without IStream_Stat capabilities.
|
|
Receives a memory handle with data buffer. If memory handle is non-null,
|
|
it is assumed to be unlocked, otherwise an internal memory handle is allocated.
|
|
In any case the object takes ownership of memory handle and will free it on
|
|
object release.
|
|
*/
|
|
static IStream* NoStatStream_Construct(HGLOBAL hGlobal)
|
|
{
|
|
NoStatStreamImpl* newStream;
|
|
|
|
newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
|
|
if (newStream!=0)
|
|
{
|
|
newStream->IStream_iface.lpVtbl = &NoStatStreamImpl_Vtbl;
|
|
newStream->ref = 1;
|
|
newStream->supportHandle = hGlobal;
|
|
|
|
if (!newStream->supportHandle)
|
|
newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
|
|
GMEM_SHARE, 0);
|
|
newStream->currentPosition.u.HighPart = 0;
|
|
newStream->currentPosition.u.LowPart = 0;
|
|
newStream->streamSize.u.HighPart = 0;
|
|
newStream->streamSize.u.LowPart = GlobalSize(newStream->supportHandle);
|
|
}
|
|
return &newStream->IStream_iface;
|
|
}
|
|
|
|
|
|
static const IStreamVtbl NoStatStreamImpl_Vtbl =
|
|
{
|
|
NoStatStreamImpl_QueryInterface,
|
|
NoStatStreamImpl_AddRef,
|
|
NoStatStreamImpl_Release,
|
|
NoStatStreamImpl_Read,
|
|
NoStatStreamImpl_Write,
|
|
NoStatStreamImpl_Seek,
|
|
NoStatStreamImpl_SetSize,
|
|
NoStatStreamImpl_CopyTo,
|
|
NoStatStreamImpl_Commit,
|
|
NoStatStreamImpl_Revert,
|
|
NoStatStreamImpl_LockRegion,
|
|
NoStatStreamImpl_UnlockRegion,
|
|
NoStatStreamImpl_Stat,
|
|
NoStatStreamImpl_Clone
|
|
};
|