From akhaldi@svn.reactos.org Sun Mar 5 21:38:01 2017 From: akhaldi@svn.reactos.org To: ros-diffs@reactos.org Subject: [ros-diffs] [akhaldi] 74107: [INETCOMM_WINETEST] Sync with Wine Staging 2.2. CORE-12823 Date: Sun, 05 Mar 2017 21:37:59 +0000 Message-ID: <167036588281.185962.751669283189847472.generated@iserv.reactos.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============8626967063374851302==" --===============8626967063374851302== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Author: akhaldi Date: Sun Mar 5 21:37:58 2017 New Revision: 74107 URL: http://svn.reactos.org/svn/reactos?rev=3D74107&view=3Drev Log: [INETCOMM_WINETEST] Sync with Wine Staging 2.2. CORE-12823 Modified: trunk/rostests/winetests/inetcomm/CMakeLists.txt trunk/rostests/winetests/inetcomm/mimeole.c Modified: trunk/rostests/winetests/inetcomm/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/inetcomm/CMa= keLists.txt?rev=3D74107&r1=3D74106&r2=3D74107&view=3Ddiff =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- trunk/rostests/winetests/inetcomm/CMakeLists.txt [iso-8859-1] (original) +++ trunk/rostests/winetests/inetcomm/CMakeLists.txt [iso-8859-1] Sun Mar 5 = 21:37:58 2017 @@ -8,5 +8,5 @@ =20 add_executable(inetcomm_winetest ${SOURCE}) set_module_type(inetcomm_winetest win32cui) -add_importlibs(inetcomm_winetest inetcomm oleaut32 ole32 msvcrt kernel32) +add_importlibs(inetcomm_winetest inetcomm oleaut32 ole32 urlmon msvcrt kerne= l32) add_rostests_file(TARGET inetcomm_winetest) Modified: trunk/rostests/winetests/inetcomm/mimeole.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/inetcomm/mim= eole.c?rev=3D74107&r1=3D74106&r2=3D74107&view=3Ddiff =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- trunk/rostests/winetests/inetcomm/mimeole.c [iso-8859-1] (original) +++ trunk/rostests/winetests/inetcomm/mimeole.c [iso-8859-1] Sun Mar 5 21:37= :58 2017 @@ -27,10 +27,46 @@ #include "ocidl.h" =20 #include "mimeole.h" +#include "wininet.h" =20 #include =20 #include "wine/test.h" + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func =3D FALSE, called_ ## func =3D FALSE + +#define SET_EXPECT(func) \ + expect_ ## func =3D TRUE + +#define CHECK_EXPECT(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + expect_ ## func =3D FALSE; \ + called_ ## func =3D TRUE; \ + }while(0) + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func =3D TRUE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func =3D called_ ## func =3D FALSE; \ + }while(0) + +DEFINE_EXPECT(Stream_Read); +DEFINE_EXPECT(Stream_Stat); +DEFINE_EXPECT(Stream_Seek); +DEFINE_EXPECT(Stream_Seek_END); +DEFINE_EXPECT(GetBindInfo); +DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE); +DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE); +DEFINE_EXPECT(ReportData); +DEFINE_EXPECT(ReportResult); =20 static const char msg1[] =3D "MIME-Version: 1.0\r\n" @@ -60,6 +96,43 @@ "More stuff\r\n" "--------------1.5.0.6--\r\n"; =20 +static const char mhtml_page1[] =3D + "MIME-Version: 1.0\r\n" + "Content-Type: multipart/related; type:=3D\"text/html\"; boundary=3D\"--= --=3D_NextPart_000_00\"\r\n" + "\r\n" + "------=3D_NextPart_000_00\r\n" + "Content-Type: text/html; charset=3D\"Windows-1252\"\r\n" + "Content-Transfer-Encoding: quoted-printable\r\n" + "\r\n" + "\r\n" + "------=3D_NextPart_000_00\r\n" + "Content-Type: Image/Jpeg\r\n" + "Content-Transfer-Encoding: base64\r\n" + "Content-Location: http://winehq.org/mhtmltest.html\r\n" + "\r\n\t\t\t\tVGVzdA=3D=3D\r\n\r\n" + "------=3D_NextPart_000_00--"; + +static WCHAR *a2w(const char *str) +{ + WCHAR *ret; + int len; + + if(!str) + return NULL; + + len =3D MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + ret =3D HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); + return ret; +} + +static int strcmp_wa(const WCHAR *strw, const char *stra) +{ + WCHAR buf[512]; + MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR)); + return lstrcmpW(strw, buf); +} + static void test_CreateVirtualStream(void) { HRESULT hr; @@ -80,6 +153,36 @@ ok(hr =3D=3D S_OK, "ret %08x\n", hr); =20 IMimeSecurity_Release(sec); +} + +static IStream *create_stream_from_string(const char *data) +{ + LARGE_INTEGER off; + IStream *stream; + HRESULT hr; + + hr =3D CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok(hr =3D=3D S_OK, "ret %08x\n", hr); + + hr =3D IStream_Write(stream, data, strlen(data), NULL); + ok(hr =3D=3D S_OK, "Write failed: %08x\n", hr); + + off.QuadPart =3D 0; + hr =3D IStream_Seek(stream, off, STREAM_SEEK_SET, NULL); + ok(hr =3D=3D S_OK, "Seek failed: %08x\n", hr); + + return stream; +} + +#define test_current_encoding(a,b) _test_current_encoding(__LINE__,a,b) +static void _test_current_encoding(unsigned line, IMimeBody *mime_body, ENCO= DINGTYPE encoding) +{ + ENCODINGTYPE current_encoding; + HRESULT hres; + + hres =3D IMimeBody_GetCurrentEncoding(mime_body, ¤t_encoding); + ok_(__FILE__,line)(hres =3D=3D S_OK, "GetCurrentEncoding failed: %08x\n"= , hres); + ok_(__FILE__,line)(current_encoding =3D=3D encoding, "encoding =3D %d, e= xpected %d\n", current_encoding, encoding); } =20 static void test_CreateBody(void) @@ -90,7 +193,6 @@ IStream *in; LARGE_INTEGER off; ULARGE_INTEGER pos; - ENCODINGTYPE enc; ULONG count, found_param, i; MIMEPARAMINFO *param_info; IMimeAllocator *alloc; @@ -103,19 +205,13 @@ ok(hr =3D=3D MIME_E_NO_DATA, "ret %08x\n", hr); ok(handle =3D=3D NULL, "handle %p\n", handle); =20 - hr =3D CreateStreamOnHGlobal(NULL, TRUE, &in); - ok(hr =3D=3D S_OK, "ret %08x\n", hr); - IStream_Write(in, msg1, sizeof(msg1) - 1, NULL); - off.QuadPart =3D 0; - IStream_Seek(in, off, STREAM_SEEK_SET, NULL); + in =3D create_stream_from_string(msg1); =20 /* Need to call InitNew before Load otherwise Load crashes with native i= netcomm */ hr =3D IMimeBody_InitNew(body); ok(hr =3D=3D S_OK, "ret %08x\n", hr); =20 - hr =3D IMimeBody_GetCurrentEncoding(body, &enc); - ok(hr =3D=3D S_OK, "ret %08x\n", hr); - ok(enc =3D=3D IET_7BIT, "encoding %d\n", enc); + test_current_encoding(body, IET_7BIT); =20 hr =3D IMimeBody_Load(body, in); ok(hr =3D=3D S_OK, "ret %08x\n", hr); @@ -137,9 +233,7 @@ hr =3D IMimeBody_IsContentType(body, "text", "plain"); todo_wine ok(hr =3D=3D S_OK, "ret %08x\n", hr); - hr =3D IMimeBody_GetCurrentEncoding(body, &enc); - ok(hr =3D=3D S_OK, "ret %08x\n", hr); - ok(enc =3D=3D IET_8BIT, "encoding %d\n", enc); + test_current_encoding(body, IET_8BIT); =20 memset(&offsets, 0xcc, sizeof(offsets)); hr =3D IMimeBody_GetOffsets(body, &offsets); @@ -197,6 +291,288 @@ IMimeBody_Release(body); } =20 +typedef struct { + IStream IStream_iface; + LONG ref; + unsigned pos; +} TestStream; + +static inline TestStream *impl_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, TestStream, IStream_iface); +} + +static HRESULT WINAPI Stream_QueryInterface(IStream *iface, REFIID riid, voi= d **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ISequentialStrea= m, riid) || IsEqualGUID(&IID_IStream, riid)) { + *ppv =3D iface; + return S_OK; + } + + ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid)); + *ppv =3D NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI Stream_AddRef(IStream *iface) +{ + TestStream *This =3D impl_from_IStream(iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI Stream_Release(IStream *iface) +{ + TestStream *This =3D impl_from_IStream(iface); + return InterlockedDecrement(&This->ref); +} + +static HRESULT WINAPI Stream_Read(IStream *iface, void *pv, ULONG cb, ULONG = *pcbRead) +{ + TestStream *This =3D impl_from_IStream(iface); + BYTE *output =3D pv; + unsigned i; + + CHECK_EXPECT(Stream_Read); + + for(i =3D 0; i < cb; i++) + output[i] =3D '0' + This->pos++; + *pcbRead =3D i; + return S_OK; +} + +static HRESULT WINAPI Stream_Write(IStream *iface, const void *pv, ULONG cb,= ULONG *pcbWritten) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static DWORD expect_seek_pos; + +static HRESULT WINAPI Stream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DW= ORD dwOrigin, + ULARGE_INTEGER *plibNewPosition) +{ + TestStream *This =3D impl_from_IStream(iface); + + if(dwOrigin =3D=3D STREAM_SEEK_END) { + CHECK_EXPECT(Stream_Seek_END); + ok(dlibMove.QuadPart =3D=3D expect_seek_pos, "unexpected seek pos %u= \n", dlibMove.u.LowPart); + if(plibNewPosition) + plibNewPosition->QuadPart =3D 10; + return S_OK; + } + + CHECK_EXPECT(Stream_Seek); + + ok(dlibMove.QuadPart =3D=3D expect_seek_pos, "unexpected seek pos %u\n",= dlibMove.u.LowPart); + ok(dwOrigin =3D=3D STREAM_SEEK_SET, "dwOrigin =3D %d\n", dwOrigin); + This->pos =3D dlibMove.QuadPart; + if(plibNewPosition) + plibNewPosition->QuadPart =3D This->pos; + return S_OK; +} + +static HRESULT WINAPI Stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSi= ze) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Stream_CopyTo(IStream *iface, IStream *pstm, ULARGE_IN= TEGER cb, + ULARGE_INTEGER *pcbRead, ULARGE_INTEGER = *pcbWritten) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Stream_Commit(IStream *iface, DWORD grfCommitFlags) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Stream_Revert(IStream *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Stream_LockRegion(IStream *iface, ULARGE_INTEGER libOf= fset, + ULARGE_INTEGER cb, DWORD dwLockType) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Stream_UnlockRegion(IStream *iface, + ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD d= wStatFlag) +{ + CHECK_EXPECT(Stream_Stat); + ok(dwStatFlag =3D=3D STATFLAG_NONAME, "dwStatFlag =3D %x\n", dwStatFlag); + return E_NOTIMPL; +} + +static HRESULT WINAPI Stream_Clone(IStream *iface, IStream **ppstm) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static /* const */ IStreamVtbl StreamVtbl =3D { + Stream_QueryInterface, + Stream_AddRef, + Stream_Release, + Stream_Read, + Stream_Write, + Stream_Seek, + Stream_SetSize, + Stream_CopyTo, + Stream_Commit, + Stream_Revert, + Stream_LockRegion, + Stream_UnlockRegion, + Stream_Stat, + Stream_Clone +}; + +static TestStream *create_test_stream(void) +{ + TestStream *stream; + stream =3D HeapAlloc(GetProcessHeap(), 0, sizeof(*stream)); + stream->IStream_iface.lpVtbl =3D &StreamVtbl; + stream->ref =3D 1; + stream->pos =3D 0; + return stream; +} + +#define test_stream_read(a,b,c,d) _test_stream_read(__LINE__,a,b,c,d) +static void _test_stream_read(unsigned line, IStream *stream, HRESULT exhres= , const char *exdata, unsigned read_size) +{ + ULONG read =3D 0xdeadbeed, exread =3D strlen(exdata); + char buf[1024]; + HRESULT hres; + + if(read_size =3D=3D -1) + read_size =3D sizeof(buf)-1; + + hres =3D IStream_Read(stream, buf, read_size, &read); + ok_(__FILE__,line)(hres =3D=3D exhres, "Read returned %08x, expected %08= x\n", hres, exhres); + ok_(__FILE__,line)(read =3D=3D exread, "unexpected read size %u, expecte= d %u\n", read, exread); + buf[read] =3D 0; + ok_(__FILE__,line)(read =3D=3D exread && !memcmp(buf, exdata, read), "un= expected data %s\n", buf); +} + +static void test_SetData(void) +{ + IStream *stream, *stream2; + TestStream *test_stream; + IMimeBody *body; + HRESULT hr; + + hr =3D CoCreateInstance(&CLSID_IMimeBody, NULL, CLSCTX_INPROC_SERVER, &I= ID_IMimeBody, (void**)&body); + ok(hr =3D=3D S_OK, "ret %08x\n", hr); + + /* Need to call InitNew before Load otherwise Load crashes with native i= netcomm */ + hr =3D IMimeBody_InitNew(body); + ok(hr =3D=3D S_OK, "ret %08x\n", hr); + + stream =3D create_stream_from_string(msg1); + hr =3D IMimeBody_Load(body, stream); + ok(hr =3D=3D S_OK, "ret %08x\n", hr); + IStream_Release(stream); + + test_stream =3D create_test_stream(); + hr =3D IMimeBody_SetData(body, IET_BINARY, "text", "plain", &IID_IStream= , &test_stream->IStream_iface); + + ok(hr =3D=3D S_OK, "ret %08x\n", hr); + hr =3D IMimeBody_IsContentType(body, "text", "plain"); + todo_wine + ok(hr =3D=3D S_OK, "ret %08x\n", hr); + + test_current_encoding(body, IET_BINARY); + + SET_EXPECT(Stream_Stat); + SET_EXPECT(Stream_Seek_END); + hr =3D IMimeBody_GetData(body, IET_BINARY, &stream); + CHECK_CALLED(Stream_Stat); + CHECK_CALLED(Stream_Seek_END); + ok(hr =3D=3D S_OK, "GetData failed %08x\n", hr); + ok(stream !=3D &test_stream->IStream_iface, "unexpected stream\n"); + + SET_EXPECT(Stream_Seek); + SET_EXPECT(Stream_Read); + test_stream_read(stream, S_OK, "012", 3); + CHECK_CALLED(Stream_Seek); + CHECK_CALLED(Stream_Read); + + SET_EXPECT(Stream_Stat); + SET_EXPECT(Stream_Seek_END); + hr =3D IMimeBody_GetData(body, IET_BINARY, &stream2); + CHECK_CALLED(Stream_Stat); + CHECK_CALLED(Stream_Seek_END); + ok(hr =3D=3D S_OK, "GetData failed %08x\n", hr); + ok(stream2 !=3D stream, "unexpected stream\n"); + + SET_EXPECT(Stream_Seek); + SET_EXPECT(Stream_Read); + test_stream_read(stream2, S_OK, "01", 2); + CHECK_CALLED(Stream_Seek); + CHECK_CALLED(Stream_Read); + + expect_seek_pos =3D 3; + SET_EXPECT(Stream_Seek); + SET_EXPECT(Stream_Read); + test_stream_read(stream, S_OK, "345", 3); + CHECK_CALLED(Stream_Seek); + CHECK_CALLED(Stream_Read); + + IStream_Release(stream); + IStream_Release(stream2); + IStream_Release(&test_stream->IStream_iface); + + stream =3D create_stream_from_string(" \t\r\n|}~YWJj ZGV|}~mZw=3D=3D \t"= ); /* "abcdefg" in base64 obscured by invalid chars */ + hr =3D IMimeBody_SetData(body, IET_BASE64, "text", "plain", &IID_IStream= , stream); + IStream_Release(stream); + ok(hr =3D=3D S_OK, "SetData failed: %08x\n", hr); + + test_current_encoding(body, IET_BASE64); + + hr =3D IMimeBody_GetData(body, IET_BINARY, &stream); + ok(hr =3D=3D S_OK, "GetData failed %08x\n", hr); + + test_stream_read(stream, S_OK, "abc", 3); + test_stream_read(stream, S_OK, "defg", -1); + + IStream_Release(stream); + + hr =3D IMimeBody_GetData(body, IET_BASE64, &stream); + ok(hr =3D=3D S_OK, "GetData failed %08x\n", hr); + + test_stream_read(stream, S_OK, " \t\r", 3); + IStream_Release(stream); + + stream =3D create_stream_from_string(" =3D3d=3D3D\"one\" \t=3D\r\ntw=3D = o=3D\nx3\n=3D34\r\n5"); + hr =3D IMimeBody_SetData(body, IET_QP, "text", "plain", &IID_IStream, st= ream); + IStream_Release(stream); + ok(hr =3D=3D S_OK, "SetData failed: %08x\n", hr); + + test_current_encoding(body, IET_QP); + + hr =3D IMimeBody_GetData(body, IET_BINARY, &stream); + ok(hr =3D=3D S_OK, "GetData failed %08x\n", hr); + + test_stream_read(stream, S_OK, " =3D=3D\"one\" \ttw=3Do=3D3\n4\r\n5", -1= ); + + IStream_Release(stream); + + IMimeBody_Release(body); +} + static void test_Allocator(void) { HRESULT hr; @@ -212,7 +588,6 @@ HRESULT hr; IMimeMessage *msg; IStream *stream; - LARGE_INTEGER pos; LONG ref; HBODY hbody, hbody2; IMimeBody *body; @@ -230,10 +605,7 @@ hr =3D MimeOleCreateMessage(NULL, &msg); ok(hr =3D=3D S_OK, "ret %08x\n", hr); =20 - CreateStreamOnHGlobal(NULL, TRUE, &stream); - IStream_Write(stream, msg1, sizeof(msg1) - 1, NULL); - pos.QuadPart =3D 0; - IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL); + stream =3D create_stream_from_string(msg1); =20 hr =3D IMimeMessage_Load(msg, stream); ok(hr =3D=3D S_OK, "ret %08x\n", hr); @@ -340,7 +712,6 @@ ok(count =3D=3D 2, "got %d\n", count); if(count =3D=3D 2) { - ENCODINGTYPE encoding; IMimeBody *attachment; PROPVARIANT prop; =20 @@ -352,9 +723,7 @@ hr =3D IMimeBody_IsContentType(attachment, "multipart", NULL); ok(hr =3D=3D S_FALSE, "ret %08x\n", hr); =20 - hr =3D IMimeBody_GetCurrentEncoding(attachment, &encoding); - ok(hr =3D=3D S_OK, "ret %08x\n", hr); - todo_wine ok(encoding =3D=3D IET_8BIT, "ret %d\n", encoding); + test_current_encoding(attachment, IET_8BIT); =20 prop.vt =3D VT_LPSTR; hr =3D IMimeBody_GetProp(attachment, "Content-Transfer-Encoding", 0,= &prop); @@ -375,9 +744,7 @@ hr =3D IMimeBody_IsContentType(attachment, "multipart", NULL); ok(hr =3D=3D S_FALSE, "ret %08x\n", hr); =20 - hr =3D IMimeBody_GetCurrentEncoding(attachment, &encoding); - ok(hr =3D=3D S_OK, "ret %08x\n", hr); - todo_wine ok(encoding =3D=3D IET_7BIT, "ret %d\n", encoding); + test_current_encoding(attachment, IET_7BIT); =20 prop.vt =3D VT_LPSTR; hr =3D IMimeBody_GetProp(attachment, "Content-Transfer-Encoding", 0,= &prop); @@ -409,6 +776,60 @@ IStream_Release(stream); =20 IStream_Release(stream); +} + +static void test_mhtml_message(void) +{ + IMimeMessage *mime_message; + IMimeBody *mime_body; + HBODY *body_list; + IStream *stream; + ULONG count; + HRESULT hres; + + hres =3D MimeOleCreateMessage(NULL, &mime_message); + ok(hres =3D=3D S_OK, "MimeOleCreateMessage failed: %08x\n", hres); + + stream =3D create_stream_from_string(mhtml_page1); + hres =3D IMimeMessage_Load(mime_message, stream); + IStream_Release(stream); + ok(hres =3D=3D S_OK, "Load failed: %08x\n", hres); + + hres =3D IMimeMessage_CountBodies(mime_message, HBODY_ROOT, TRUE, &count= ); + ok(hres =3D=3D S_OK, "CountBodies failed: %08x\n", hres); + ok(count =3D=3D 3, "got %d\n", count); + + hres =3D IMimeMessage_GetAttachments(mime_message, &count, &body_list); + ok(hres =3D=3D S_OK, "GetAttachments failed: %08x\n", hres); + ok(count =3D=3D 2, "count =3D %u\n", count); + + hres =3D IMimeMessage_BindToObject(mime_message, body_list[0], &IID_IMim= eBody, (void**)&mime_body); + ok(hres =3D=3D S_OK, "BindToObject failed: %08x\n", hres); + + hres =3D IMimeBody_GetData(mime_body, IET_BINARY, &stream); + ok(hres =3D=3D S_OK, "GetData failed: %08x\n", hres); + test_stream_read(stream, S_OK, "", -1); + IStream_Release(stream); + + test_current_encoding(mime_body, IET_QP); + + IMimeBody_Release(mime_body); + + hres =3D IMimeMessage_BindToObject(mime_message, body_list[1], &IID_IMim= eBody, (void**)&mime_body); + ok(hres =3D=3D S_OK, "BindToObject failed: %08x\n", hres); + + test_current_encoding(mime_body, IET_BASE64); + + hres =3D IMimeBody_GetData(mime_body, IET_BINARY, &stream); + ok(hres =3D=3D S_OK, "GetData failed: %08x\n", hres); + test_stream_read(stream, S_OK, "Test", -1); + IStream_Release(stream); + + IMimeBody_Release(mime_body); + + CoTaskMemFree(body_list); + + IMimeMessage_Release(mime_message); } =20 static void test_MessageSetProp(void) @@ -760,12 +1181,475 @@ IMimePropertySchema_Release(schema); } =20 +typedef struct { + const char *url; + const char *content; + const char *mime; + const char *data; +} mhtml_binding_test_t; + +static const mhtml_binding_test_t binding_tests[] =3D { + { + "mhtml:file://%s", + mhtml_page1, + "text/html", + "" + }, + { + "mhtml:file://%s!http://winehq.org/mhtmltest.html", + mhtml_page1, + "Image/Jpeg", + "Test" + } +}; + +static const mhtml_binding_test_t *current_binding_test; +static IInternetProtocol *current_binding_protocol; + +static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, REFI= ID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetBindInf= o, riid)) { + *ppv =3D iface; + return S_OK; + } + + *ppv =3D NULL; + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface) +{ + return 2; +} + +static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface) +{ + return 1; +} + +static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *= grfBINDF, BINDINFO *pbindinfo) +{ + CHECK_EXPECT(GetBindInfo); + + ok(grfBINDF !=3D NULL, "grfBINDF =3D=3D NULL\n"); + ok(pbindinfo !=3D NULL, "pbindinfo =3D=3D NULL\n"); + ok(pbindinfo->cbSize =3D=3D sizeof(BINDINFO), "wrong size of pbindinfo: = %d\n", pbindinfo->cbSize); + + *grfBINDF =3D BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA |= BINDF_FROMURLMON | BINDF_NEEDFILE; + return S_OK; +} + +static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG= ulStringType, LPOLESTR *ppwzStr, + ULONG cEl, ULONG *pcElFetched) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static IInternetBindInfoVtbl InternetBindInfoVtbl =3D { + BindInfo_QueryInterface, + BindInfo_AddRef, + BindInfo_Release, + BindInfo_GetBindInfo, + BindInfo_GetBindString +}; + +static IInternetBindInfo bind_info =3D { + &InternetBindInfoVtbl +}; + +static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface= , REFIID riid, void **ppv) +{ + ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid)); + *ppv =3D NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, = REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(&CLSID_MimeEdit, guidService)) { + *ppv =3D NULL; + return E_NOINTERFACE; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + return E_FAIL; +} + +static /* const */ IServiceProviderVtbl ServiceProviderVtbl =3D { + ServiceProvider_QueryInterface, + ServiceProvider_AddRef, + ServiceProvider_Release, + ServiceProvider_QueryService +}; + +static IServiceProvider service_provider =3D { &ServiceProviderVtbl }; + +static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *ifa= ce, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtoco= lSink, riid)) { + *ppv =3D iface; + return S_OK; + } + + if(IsEqualGUID(&IID_IServiceProvider, riid)) { + *ppv =3D &service_provider; + return S_OK; + } + + *ppv =3D NULL; + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI ProtocolSink_AddRef(IInternetProtocolSink *iface) +{ + return 2; +} + +static ULONG WINAPI ProtocolSink_Release(IInternetProtocolSink *iface) +{ + return 1; +} + +static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROT= OCOLDATA *pProtocolData) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *ifa= ce, ULONG ulStatusCode, + const WCHAR *szStatusText) +{ + switch(ulStatusCode) { + case BINDSTATUS_MIMETYPEAVAILABLE: + CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + ok(!strcmp_wa(szStatusText, current_binding_test->mime), "status tex= t %s\n", wine_dbgstr_w(szStatusText)); + return S_OK; + case BINDSTATUS_CACHEFILENAMEAVAILABLE: + CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE); + return S_OK; + default: + ok(0, "unexpected call %u %s\n", ulStatusCode, wine_dbgstr_w(szStatu= sText)); + } + + return E_NOTIMPL; +} + +static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, = DWORD grfBSCF, ULONG ulProgress, + ULONG ulProgressMax) +{ + char buf[1024]; + DWORD read; + HRESULT hres; + + CHECK_EXPECT(ReportData); + + ok(!ulProgress, "ulProgress =3D %u\n", ulProgress); + ok(ulProgress =3D=3D ulProgressMax, "ulProgress !=3D ulProgressMax\n"); + ok(grfBSCF =3D=3D (BSCF_FIRSTDATANOTIFICATION | BSCF_INTERMEDIATEDATANOT= IFICATION + | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE | B= SCF_AVAILABLEDATASIZEUNKNOWN), + "grcf =3D %08x\n", grfBSCF); + + hres =3D IInternetProtocol_Read(current_binding_protocol, buf, sizeof(bu= f), &read); + ok(hres =3D=3D S_OK, "Read failed: %08x\n", hres); + buf[read] =3D 0; + ok(!strcmp(buf, current_binding_test->data), "unexpected data: %s\n", bu= f); + + hres =3D IInternetProtocol_Read(current_binding_protocol, buf, sizeof(bu= f), &read); + ok(hres =3D=3D S_FALSE, "Read failed: %08x\n", hres); + return S_OK; +} + +static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface= , HRESULT hrResult, DWORD dwError, + LPCWSTR szResult) +{ + CHECK_EXPECT(ReportResult); + ok(hrResult =3D=3D S_OK, "hrResult =3D %08x\n", hrResult); + ok(!dwError, "dwError =3D %u\n", dwError); + ok(!szResult, "szResult =3D %s\n", wine_dbgstr_w(szResult)); + return S_OK; +} + +static IInternetProtocolSinkVtbl InternetProtocolSinkVtbl =3D { + ProtocolSink_QueryInterface, + ProtocolSink_AddRef, + ProtocolSink_Release, + ProtocolSink_Switch, + ProtocolSink_ReportProgress, + ProtocolSink_ReportData, + ProtocolSink_ReportResult +}; + +static IInternetProtocolSink protocol_sink =3D { &InternetProtocolSinkVtbl }; + +static void test_mhtml_protocol_binding(const mhtml_binding_test_t *test) +{ + char file_name[MAX_PATH+32], *p, urla[INTERNET_MAX_URL_LENGTH]; + WCHAR test_url[INTERNET_MAX_URL_LENGTH]; + IInternetProtocol *protocol; + IUnknown *unk; + HRESULT hres; + HANDLE file; + DWORD size; + + p =3D file_name + GetCurrentDirectoryA(sizeof(file_name), file_name); + *p++ =3D '\\'; + strcpy(p, "winetest.mht"); + + file =3D CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(file !=3D INVALID_HANDLE_VALUE, "CreateFile failed\n"); + + WriteFile(file, test->content, strlen(test->content), &size, NULL); + CloseHandle(file); + + sprintf(urla, test->url, file_name); + MultiByteToWideChar(CP_ACP, 0, urla, -1, test_url, sizeof(test_url)/size= of(WCHAR)); + + hres =3D CoCreateInstance(&CLSID_IMimeHtmlProtocol, NULL, CLSCTX_INPROC_= SERVER, &IID_IInternetProtocol, (void**)&protocol); + ok(hres =3D=3D S_OK, "Could not create protocol handler: %08x\n", hres); + + hres =3D IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtoc= olEx, (void**)&unk); + ok(hres =3D=3D E_NOINTERFACE, "Could get IInternetProtocolEx\n"); + + current_binding_test =3D test; + current_binding_protocol =3D protocol; + + SET_EXPECT(GetBindInfo); + SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE); + SET_EXPECT(ReportData); + SET_EXPECT(ReportResult); + hres =3D IInternetProtocol_Start(protocol, test_url, &protocol_sink, &bi= nd_info, 0, 0); + ok(hres =3D=3D S_OK, "Start failed: %08x\n", hres); + CHECK_CALLED(GetBindInfo); + CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); + todo_wine CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE); + CHECK_CALLED(ReportData); + CHECK_CALLED(ReportResult); + + IInternetProtocol_Release(protocol); + ok(DeleteFileA("winetest.mht"), "DeleteFile failed: %u\n", GetLastError(= )); +} + +static const struct { + const char *base_url; + const char *relative_url; + const char *expected_result; + BOOL todo; +} combine_tests[] =3D { + { + "mhtml:file:///c:/dir/test.mht", "http://test.org", + "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org" + }, { + "mhtml:file:///c:/dir/test.mht", "3D\"http://test.org\"", + "mhtml:file:///c:/dir/test.mht!x-usc:3D\"http://test.org\"" + }, { + "mhtml:file:///c:/dir/test.mht", "123abc", + "mhtml:file:///c:/dir/test.mht!x-usc:123abc" + }, { + "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "123abc", + "mhtml:file:///c:/dir/test.mht!x-usc:123abc" + }, { + "MhtMl:file:///c:/dir/test.mht!x-usc:http://test.org/dir/dir2/file.h= tml", "../..", + "mhtml:file:///c:/dir/test.mht!x-usc:../.." + }, {"mhtml:file:///c:/dir/test.mht!x-usc:file:///c:/dir/dir2/file.html",= "../..", + "mhtml:file:///c:/dir/test.mht!x-usc:../.." + }, { + "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "", + "mhtml:file:///c:/dir/test.mht" + }, { + "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "mhtml:file:/= //d:/file.html", + "file:///d:/file.html", TRUE + }, { + "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "mhtml:file:/= //c:/dir2/test.mht!x-usc:http://test.org", + "mhtml:file:///c:/dir2/test.mht!x-usc:http://test.org", TRUE + }, { + "mhtml:file:///c:/dir/test.mht!http://test.org", "123abc", + "mhtml:file:///c:/dir/test.mht!x-usc:123abc" + }, { + "mhtml:file:///c:/dir/test.mht!http://test.org", "", + "mhtml:file:///c:/dir/test.mht" + } +}; + +static void test_mhtml_protocol_info(void) +{ + WCHAR *base_url, *relative_url, combined_url[INTERNET_MAX_URL_LENGTH]; + IInternetProtocolInfo *protocol_info; + DWORD combined_len; + unsigned i, exlen; + HRESULT hres; + + static const WCHAR http_url[] =3D {'h','t','t','p',':','/','/','t','e','= s','t','.','o','r','g',0}; + + hres =3D CoCreateInstance(&CLSID_IMimeHtmlProtocol, NULL, CLSCTX_INPROC_= SERVER, + &IID_IInternetProtocolInfo, (void**)&protocol_in= fo); + ok(hres =3D=3D S_OK, "Could not create protocol info: %08x\n", hres); + + for(i =3D 0; i < sizeof(combine_tests)/sizeof(*combine_tests); i++) { + base_url =3D a2w(combine_tests[i].base_url); + relative_url =3D a2w(combine_tests[i].relative_url); + + combined_len =3D 0xdeadbeef; + hres =3D IInternetProtocolInfo_CombineUrl(protocol_info, base_url, r= elative_url, ICU_BROWSER_MODE, + combined_url, sizeof(combine= d_url)/sizeof(WCHAR), &combined_len, 0); + todo_wine_if(combine_tests[i].todo) + ok(hres =3D=3D S_OK, "[%u] CombineUrl failed: %08x\n", i, hres); + if(SUCCEEDED(hres)) { + exlen =3D strlen(combine_tests[i].expected_result); + ok(combined_len =3D=3D exlen, "[%u] combined len is %u, expected= %u\n", i, combined_len, exlen); + ok(!strcmp_wa(combined_url, combine_tests[i].expected_result), "= [%u] combined URL is %s, expected %s\n", + i, wine_dbgstr_w(combined_url), combine_tests[i].expected_res= ult); + + combined_len =3D 0xdeadbeef; + hres =3D IInternetProtocolInfo_CombineUrl(protocol_info, base_ur= l, relative_url, ICU_BROWSER_MODE, + combined_url, exlen, &co= mbined_len, 0); + ok(hres =3D=3D E_FAIL, "[%u] CombineUrl returned: %08x\n", i, hr= es); + ok(!combined_len, "[%u] combined_len =3D %u\n", i, combined_len); + } + + HeapFree(GetProcessHeap(), 0, base_url); + HeapFree(GetProcessHeap(), 0, relative_url); + } + + hres =3D IInternetProtocolInfo_CombineUrl(protocol_info, http_url, http_= url, ICU_BROWSER_MODE, + combined_url, sizeof(combined_ur= l)/sizeof(WCHAR), &combined_len, 0); + ok(hres =3D=3D E_FAIL, "CombineUrl failed: %08x\n", hres); + + IInternetProtocolInfo_Release(protocol_info); +} + +static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID riid, voi= d **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI outer_AddRef(IUnknown *iface) +{ + return 2; +} + +static ULONG WINAPI outer_Release(IUnknown *iface) +{ + return 1; +} + +static /* const */ IUnknownVtbl outer_vtbl =3D { + outer_QueryInterface, + outer_AddRef, + outer_Release +}; + +static BOOL broken_mhtml_resolver; + +static void test_mhtml_protocol(void) +{ + IUnknown outer =3D { &outer_vtbl }; + IClassFactory *class_factory; + IUnknown *unk, *unk2; + unsigned i; + HRESULT hres; + + /* test class factory */ + hres =3D CoGetClassObject(&CLSID_IMimeHtmlProtocol, CLSCTX_INPROC_SERVER= , NULL, &IID_IUnknown, (void**)&unk); + ok(hres =3D=3D S_OK, "CoGetClassObject failed: %08x\n", hres); + + hres =3D IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void*= *)&unk2); + ok(hres =3D=3D E_NOINTERFACE, "IInternetProtocolInfo supported\n"); + + hres =3D IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&class= _factory); + ok(hres =3D=3D S_OK, "Could not get IClassFactory iface: %08x\n", hres); + IUnknown_Release(unk); + + hres =3D IClassFactory_CreateInstance(class_factory, &outer, &IID_IUnkno= wn, (void**)&unk); + ok(hres =3D=3D S_OK, "CreateInstance returned: %08x\n", hres); + hres =3D IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&u= nk2); + ok(hres =3D=3D S_OK, "Could not get IInternetProtocol iface: %08x\n", hr= es); + IUnknown_Release(unk2); + IUnknown_Release(unk); + + hres =3D IClassFactory_CreateInstance(class_factory, (IUnknown*)0xdeadbe= ef, &IID_IInternetProtocol, (void**)&unk2); + ok(hres =3D=3D CLASS_E_NOAGGREGATION, "CreateInstance returned: %08x\n",= hres); + + IClassFactory_Release(class_factory); + + if(!broken_mhtml_resolver) + test_mhtml_protocol_info(); + + for(i =3D 0; i < sizeof(binding_tests)/sizeof(*binding_tests); i++) + test_mhtml_protocol_binding(binding_tests + i); +} + +static void test_MimeOleObjectFromMoniker(void) +{ + IMoniker *mon, *new_mon; + WCHAR *mhtml_url, *url; + IBindCtx *bind_ctx; + IUnknown *unk; + unsigned i; + HRESULT hres; + + static const struct { + const char *url; + const char *mhtml_url; + } tests[] =3D { + {"file:///x:\\dir\\file.mht", "mhtml:file://x:\\dir\\file.mht"}, + {"file:///x:/dir/file.mht", "mhtml:file://x:\\dir\\file.mht"}, + {"http://www.winehq.org/index.html?query#hash", "mhtml:http://www.wi= nehq.org/index.html?query#hash"}, + {"../test.mht", "mhtml:../test.mht"} + }; + + for(i =3D 0; i < sizeof(tests)/sizeof(*tests); i++) { + url =3D a2w(tests[i].url); + hres =3D CreateURLMoniker(NULL, url, &mon); + ok(hres =3D=3D S_OK, "CreateURLMoniker failed: %08x\n", hres); + HeapFree(GetProcessHeap(), 0, url); + + hres =3D CreateBindCtx(0, &bind_ctx); + ok(hres =3D=3D S_OK, "CreateBindCtx failed: %08x\n", hres); + + hres =3D MimeOleObjectFromMoniker(0, mon, bind_ctx, &IID_IUnknown, (= void**)&unk, &new_mon); + ok(hres =3D=3D S_OK || broken(!i && hres =3D=3D INET_E_RESOURCE_NOT_= FOUND), "MimeOleObjectFromMoniker failed: %08x\n", hres); + IBindCtx_Release(bind_ctx); + if(hres =3D=3D INET_E_RESOURCE_NOT_FOUND) { /* winxp */ + win_skip("Broken MHTML behaviour found. Skipping some tests.\n"); + broken_mhtml_resolver =3D TRUE; + return; + } + + hres =3D IMoniker_GetDisplayName(new_mon, NULL, NULL, &mhtml_url); + ok(hres =3D=3D S_OK, "GetDisplayName failed: %08x\n", hres); + ok(!strcmp_wa(mhtml_url, tests[i].mhtml_url), "[%d] unexpected mhtml= URL: %s\n", i, wine_dbgstr_w(mhtml_url)); + CoTaskMemFree(mhtml_url); + + IUnknown_Release(unk); + IMoniker_Release(new_mon); + IMoniker_Release(mon); + } +} + START_TEST(mimeole) { OleInitialize(NULL); test_CreateVirtualStream(); test_CreateSecurity(); test_CreateBody(); + test_SetData(); test_Allocator(); test_CreateMessage(); test_MessageSetProp(); @@ -774,5 +1658,8 @@ test_BindToObject(); test_BodyDeleteProp(); test_MimeOleGetPropertySchema(); + test_mhtml_message(); + test_MimeOleObjectFromMoniker(); + test_mhtml_protocol(); OleUninitialize(); } --===============8626967063374851302==--