Author: akhaldi
Date: Sun Mar 5 21:37:58 2017
New Revision: 74107
URL:
http://svn.reactos.org/svn/reactos?rev=74107&view=rev
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/CMakeL…
==============================================================================
--- 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 @@
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 kernel32)
add_rostests_file(TARGET inetcomm_winetest)
Modified: trunk/rostests/winetests/inetcomm/mimeole.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/inetcomm/mimeol…
==============================================================================
--- 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"
#include "mimeole.h"
+#include "wininet.h"
#include <stdio.h>
#include "wine/test.h"
+
+#define DEFINE_EXPECT(func) \
+ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+ expect_ ## func = TRUE
+
+#define CHECK_EXPECT(func) \
+ do { \
+ ok(expect_ ##func, "unexpected call " #func "\n"); \
+ expect_ ## func = FALSE; \
+ called_ ## func = TRUE; \
+ }while(0)
+
+#define CHECK_EXPECT2(func) \
+ do { \
+ ok(expect_ ##func, "unexpected call " #func "\n"); \
+ called_ ## func = TRUE; \
+ }while(0)
+
+#define CHECK_CALLED(func) \
+ do { \
+ ok(called_ ## func, "expected " #func "\n"); \
+ expect_ ## func = called_ ## func = 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);
static const char msg1[] =
"MIME-Version: 1.0\r\n"
@@ -60,6 +96,43 @@
"More stuff\r\n"
"--------------1.5.0.6--\r\n";
+static const char mhtml_page1[] =
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: multipart/related; type:=\"text/html\";
boundary=\"----=_NextPart_000_00\"\r\n"
+ "\r\n"
+ "------=_NextPart_000_00\r\n"
+ "Content-Type: text/html; charset=\"Windows-1252\"\r\n"
+ "Content-Transfer-Encoding: quoted-printable\r\n"
+ "\r\n"
+ "<HTML></HTML>\r\n"
+ "------=_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==\r\n\r\n"
+ "------=_NextPart_000_00--";
+
+static WCHAR *a2w(const char *str)
+{
+ WCHAR *ret;
+ int len;
+
+ if(!str)
+ return NULL;
+
+ len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+ ret = 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 == S_OK, "ret %08x\n", hr);
IMimeSecurity_Release(sec);
+}
+
+static IStream *create_stream_from_string(const char *data)
+{
+ LARGE_INTEGER off;
+ IStream *stream;
+ HRESULT hr;
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
+ ok(hr == S_OK, "ret %08x\n", hr);
+
+ hr = IStream_Write(stream, data, strlen(data), NULL);
+ ok(hr == S_OK, "Write failed: %08x\n", hr);
+
+ off.QuadPart = 0;
+ hr = IStream_Seek(stream, off, STREAM_SEEK_SET, NULL);
+ ok(hr == 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, ENCODINGTYPE
encoding)
+{
+ ENCODINGTYPE current_encoding;
+ HRESULT hres;
+
+ hres = IMimeBody_GetCurrentEncoding(mime_body, ¤t_encoding);
+ ok_(__FILE__,line)(hres == S_OK, "GetCurrentEncoding failed: %08x\n",
hres);
+ ok_(__FILE__,line)(current_encoding == encoding, "encoding = %d, expected
%d\n", current_encoding, encoding);
}
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 == MIME_E_NO_DATA, "ret %08x\n", hr);
ok(handle == NULL, "handle %p\n", handle);
- hr = CreateStreamOnHGlobal(NULL, TRUE, &in);
- ok(hr == S_OK, "ret %08x\n", hr);
- IStream_Write(in, msg1, sizeof(msg1) - 1, NULL);
- off.QuadPart = 0;
- IStream_Seek(in, off, STREAM_SEEK_SET, NULL);
+ in = create_stream_from_string(msg1);
/* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
hr = IMimeBody_InitNew(body);
ok(hr == S_OK, "ret %08x\n", hr);
- hr = IMimeBody_GetCurrentEncoding(body, &enc);
- ok(hr == S_OK, "ret %08x\n", hr);
- ok(enc == IET_7BIT, "encoding %d\n", enc);
+ test_current_encoding(body, IET_7BIT);
hr = IMimeBody_Load(body, in);
ok(hr == S_OK, "ret %08x\n", hr);
@@ -137,9 +233,7 @@
hr = IMimeBody_IsContentType(body, "text", "plain");
todo_wine
ok(hr == S_OK, "ret %08x\n", hr);
- hr = IMimeBody_GetCurrentEncoding(body, &enc);
- ok(hr == S_OK, "ret %08x\n", hr);
- ok(enc == IET_8BIT, "encoding %d\n", enc);
+ test_current_encoding(body, IET_8BIT);
memset(&offsets, 0xcc, sizeof(offsets));
hr = IMimeBody_GetOffsets(body, &offsets);
@@ -197,6 +291,288 @@
IMimeBody_Release(body);
}
+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, void **ppv)
+{
+ if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ISequentialStream,
riid) || IsEqualGUID(&IID_IStream, riid)) {
+ *ppv = iface;
+ return S_OK;
+ }
+
+ ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI Stream_AddRef(IStream *iface)
+{
+ TestStream *This = impl_from_IStream(iface);
+ return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI Stream_Release(IStream *iface)
+{
+ TestStream *This = impl_from_IStream(iface);
+ return InterlockedDecrement(&This->ref);
+}
+
+static HRESULT WINAPI Stream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
+{
+ TestStream *This = impl_from_IStream(iface);
+ BYTE *output = pv;
+ unsigned i;
+
+ CHECK_EXPECT(Stream_Read);
+
+ for(i = 0; i < cb; i++)
+ output[i] = '0' + This->pos++;
+ *pcbRead = 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, DWORD
dwOrigin,
+ ULARGE_INTEGER *plibNewPosition)
+{
+ TestStream *This = impl_from_IStream(iface);
+
+ if(dwOrigin == STREAM_SEEK_END) {
+ CHECK_EXPECT(Stream_Seek_END);
+ ok(dlibMove.QuadPart == expect_seek_pos, "unexpected seek pos %u\n",
dlibMove.u.LowPart);
+ if(plibNewPosition)
+ plibNewPosition->QuadPart = 10;
+ return S_OK;
+ }
+
+ CHECK_EXPECT(Stream_Seek);
+
+ ok(dlibMove.QuadPart == expect_seek_pos, "unexpected seek pos %u\n",
dlibMove.u.LowPart);
+ ok(dwOrigin == STREAM_SEEK_SET, "dwOrigin = %d\n", dwOrigin);
+ This->pos = dlibMove.QuadPart;
+ if(plibNewPosition)
+ plibNewPosition->QuadPart = This->pos;
+ return S_OK;
+}
+
+static HRESULT WINAPI Stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Stream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER 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 libOffset,
+ 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 dwStatFlag)
+{
+ CHECK_EXPECT(Stream_Stat);
+ ok(dwStatFlag == STATFLAG_NONAME, "dwStatFlag = %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 = {
+ 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 = HeapAlloc(GetProcessHeap(), 0, sizeof(*stream));
+ stream->IStream_iface.lpVtbl = &StreamVtbl;
+ stream->ref = 1;
+ stream->pos = 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 = 0xdeadbeed, exread = strlen(exdata);
+ char buf[1024];
+ HRESULT hres;
+
+ if(read_size == -1)
+ read_size = sizeof(buf)-1;
+
+ hres = IStream_Read(stream, buf, read_size, &read);
+ ok_(__FILE__,line)(hres == exhres, "Read returned %08x, expected %08x\n",
hres, exhres);
+ ok_(__FILE__,line)(read == exread, "unexpected read size %u, expected
%u\n", read, exread);
+ buf[read] = 0;
+ ok_(__FILE__,line)(read == exread && !memcmp(buf, exdata, read),
"unexpected data %s\n", buf);
+}
+
+static void test_SetData(void)
+{
+ IStream *stream, *stream2;
+ TestStream *test_stream;
+ IMimeBody *body;
+ HRESULT hr;
+
+ hr = CoCreateInstance(&CLSID_IMimeBody, NULL, CLSCTX_INPROC_SERVER,
&IID_IMimeBody, (void**)&body);
+ ok(hr == S_OK, "ret %08x\n", hr);
+
+ /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
+ hr = IMimeBody_InitNew(body);
+ ok(hr == S_OK, "ret %08x\n", hr);
+
+ stream = create_stream_from_string(msg1);
+ hr = IMimeBody_Load(body, stream);
+ ok(hr == S_OK, "ret %08x\n", hr);
+ IStream_Release(stream);
+
+ test_stream = create_test_stream();
+ hr = IMimeBody_SetData(body, IET_BINARY, "text", "plain",
&IID_IStream, &test_stream->IStream_iface);
+
+ ok(hr == S_OK, "ret %08x\n", hr);
+ hr = IMimeBody_IsContentType(body, "text", "plain");
+ todo_wine
+ ok(hr == S_OK, "ret %08x\n", hr);
+
+ test_current_encoding(body, IET_BINARY);
+
+ SET_EXPECT(Stream_Stat);
+ SET_EXPECT(Stream_Seek_END);
+ hr = IMimeBody_GetData(body, IET_BINARY, &stream);
+ CHECK_CALLED(Stream_Stat);
+ CHECK_CALLED(Stream_Seek_END);
+ ok(hr == S_OK, "GetData failed %08x\n", hr);
+ ok(stream != &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 = IMimeBody_GetData(body, IET_BINARY, &stream2);
+ CHECK_CALLED(Stream_Stat);
+ CHECK_CALLED(Stream_Seek_END);
+ ok(hr == S_OK, "GetData failed %08x\n", hr);
+ ok(stream2 != 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 = 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 = create_stream_from_string(" \t\r\n|}~YWJj ZGV|}~mZw== \t"); /*
"abcdefg" in base64 obscured by invalid chars */
+ hr = IMimeBody_SetData(body, IET_BASE64, "text", "plain",
&IID_IStream, stream);
+ IStream_Release(stream);
+ ok(hr == S_OK, "SetData failed: %08x\n", hr);
+
+ test_current_encoding(body, IET_BASE64);
+
+ hr = IMimeBody_GetData(body, IET_BINARY, &stream);
+ ok(hr == 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 = IMimeBody_GetData(body, IET_BASE64, &stream);
+ ok(hr == S_OK, "GetData failed %08x\n", hr);
+
+ test_stream_read(stream, S_OK, " \t\r", 3);
+ IStream_Release(stream);
+
+ stream = create_stream_from_string(" =3d=3D\"one\" \t=\r\ntw=
o=\nx3\n=34\r\n5");
+ hr = IMimeBody_SetData(body, IET_QP, "text", "plain",
&IID_IStream, stream);
+ IStream_Release(stream);
+ ok(hr == S_OK, "SetData failed: %08x\n", hr);
+
+ test_current_encoding(body, IET_QP);
+
+ hr = IMimeBody_GetData(body, IET_BINARY, &stream);
+ ok(hr == S_OK, "GetData failed %08x\n", hr);
+
+ test_stream_read(stream, S_OK, " ==\"one\" \ttw=o=3\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 = MimeOleCreateMessage(NULL, &msg);
ok(hr == S_OK, "ret %08x\n", hr);
- CreateStreamOnHGlobal(NULL, TRUE, &stream);
- IStream_Write(stream, msg1, sizeof(msg1) - 1, NULL);
- pos.QuadPart = 0;
- IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
+ stream = create_stream_from_string(msg1);
hr = IMimeMessage_Load(msg, stream);
ok(hr == S_OK, "ret %08x\n", hr);
@@ -340,7 +712,6 @@
ok(count == 2, "got %d\n", count);
if(count == 2)
{
- ENCODINGTYPE encoding;
IMimeBody *attachment;
PROPVARIANT prop;
@@ -352,9 +723,7 @@
hr = IMimeBody_IsContentType(attachment, "multipart", NULL);
ok(hr == S_FALSE, "ret %08x\n", hr);
- hr = IMimeBody_GetCurrentEncoding(attachment, &encoding);
- ok(hr == S_OK, "ret %08x\n", hr);
- todo_wine ok(encoding == IET_8BIT, "ret %d\n", encoding);
+ test_current_encoding(attachment, IET_8BIT);
prop.vt = VT_LPSTR;
hr = IMimeBody_GetProp(attachment, "Content-Transfer-Encoding", 0,
&prop);
@@ -375,9 +744,7 @@
hr = IMimeBody_IsContentType(attachment, "multipart", NULL);
ok(hr == S_FALSE, "ret %08x\n", hr);
- hr = IMimeBody_GetCurrentEncoding(attachment, &encoding);
- ok(hr == S_OK, "ret %08x\n", hr);
- todo_wine ok(encoding == IET_7BIT, "ret %d\n", encoding);
+ test_current_encoding(attachment, IET_7BIT);
prop.vt = VT_LPSTR;
hr = IMimeBody_GetProp(attachment, "Content-Transfer-Encoding", 0,
&prop);
@@ -409,6 +776,60 @@
IStream_Release(stream);
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 = MimeOleCreateMessage(NULL, &mime_message);
+ ok(hres == S_OK, "MimeOleCreateMessage failed: %08x\n", hres);
+
+ stream = create_stream_from_string(mhtml_page1);
+ hres = IMimeMessage_Load(mime_message, stream);
+ IStream_Release(stream);
+ ok(hres == S_OK, "Load failed: %08x\n", hres);
+
+ hres = IMimeMessage_CountBodies(mime_message, HBODY_ROOT, TRUE, &count);
+ ok(hres == S_OK, "CountBodies failed: %08x\n", hres);
+ ok(count == 3, "got %d\n", count);
+
+ hres = IMimeMessage_GetAttachments(mime_message, &count, &body_list);
+ ok(hres == S_OK, "GetAttachments failed: %08x\n", hres);
+ ok(count == 2, "count = %u\n", count);
+
+ hres = IMimeMessage_BindToObject(mime_message, body_list[0], &IID_IMimeBody,
(void**)&mime_body);
+ ok(hres == S_OK, "BindToObject failed: %08x\n", hres);
+
+ hres = IMimeBody_GetData(mime_body, IET_BINARY, &stream);
+ ok(hres == S_OK, "GetData failed: %08x\n", hres);
+ test_stream_read(stream, S_OK, "<HTML></HTML>", -1);
+ IStream_Release(stream);
+
+ test_current_encoding(mime_body, IET_QP);
+
+ IMimeBody_Release(mime_body);
+
+ hres = IMimeMessage_BindToObject(mime_message, body_list[1], &IID_IMimeBody,
(void**)&mime_body);
+ ok(hres == S_OK, "BindToObject failed: %08x\n", hres);
+
+ test_current_encoding(mime_body, IET_BASE64);
+
+ hres = IMimeBody_GetData(mime_body, IET_BINARY, &stream);
+ ok(hres == 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);
}
static void test_MessageSetProp(void)
@@ -760,12 +1181,475 @@
IMimePropertySchema_Release(schema);
}
+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[] = {
+ {
+ "mhtml:file://%s",
+ mhtml_page1,
+ "text/html",
+ "<HTML></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, REFIID riid, void
**ppv)
+{
+ if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetBindInfo,
riid)) {
+ *ppv = iface;
+ return S_OK;
+ }
+
+ *ppv = 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 != NULL, "grfBINDF == NULL\n");
+ ok(pbindinfo != NULL, "pbindinfo == NULL\n");
+ ok(pbindinfo->cbSize == sizeof(BINDINFO), "wrong size of pbindinfo:
%d\n", pbindinfo->cbSize);
+
+ *grfBINDF = 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 = {
+ BindInfo_QueryInterface,
+ BindInfo_AddRef,
+ BindInfo_Release,
+ BindInfo_GetBindInfo,
+ BindInfo_GetBindString
+};
+
+static IInternetBindInfo bind_info = {
+ &InternetBindInfoVtbl
+};
+
+static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID
riid, void **ppv)
+{
+ ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
+ *ppv = 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 = NULL;
+ return E_NOINTERFACE;
+ }
+
+ ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService));
+ return E_FAIL;
+}
+
+static /* const */ IServiceProviderVtbl ServiceProviderVtbl = {
+ ServiceProvider_QueryInterface,
+ ServiceProvider_AddRef,
+ ServiceProvider_Release,
+ ServiceProvider_QueryService
+};
+
+static IServiceProvider service_provider = { &ServiceProviderVtbl };
+
+static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID
riid, void **ppv)
+{
+ if(IsEqualGUID(&IID_IUnknown, riid) ||
IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
+ *ppv = iface;
+ return S_OK;
+ }
+
+ if(IsEqualGUID(&IID_IServiceProvider, riid)) {
+ *ppv = &service_provider;
+ return S_OK;
+ }
+
+ *ppv = 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, PROTOCOLDATA
*pProtocolData)
+{
+ ok(0, "unexpected call\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG
ulStatusCode,
+ const WCHAR *szStatusText)
+{
+ switch(ulStatusCode) {
+ case BINDSTATUS_MIMETYPEAVAILABLE:
+ CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
+ ok(!strcmp_wa(szStatusText, current_binding_test->mime), "status text
%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(szStatusText));
+ }
+
+ 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 = %u\n", ulProgress);
+ ok(ulProgress == ulProgressMax, "ulProgress != ulProgressMax\n");
+ ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_INTERMEDIATEDATANOTIFICATION
+ | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE |
BSCF_AVAILABLEDATASIZEUNKNOWN),
+ "grcf = %08x\n", grfBSCF);
+
+ hres = IInternetProtocol_Read(current_binding_protocol, buf, sizeof(buf),
&read);
+ ok(hres == S_OK, "Read failed: %08x\n", hres);
+ buf[read] = 0;
+ ok(!strcmp(buf, current_binding_test->data), "unexpected data: %s\n",
buf);
+
+ hres = IInternetProtocol_Read(current_binding_protocol, buf, sizeof(buf),
&read);
+ ok(hres == 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 == S_OK, "hrResult = %08x\n", hrResult);
+ ok(!dwError, "dwError = %u\n", dwError);
+ ok(!szResult, "szResult = %s\n", wine_dbgstr_w(szResult));
+ return S_OK;
+}
+
+static IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
+ ProtocolSink_QueryInterface,
+ ProtocolSink_AddRef,
+ ProtocolSink_Release,
+ ProtocolSink_Switch,
+ ProtocolSink_ReportProgress,
+ ProtocolSink_ReportData,
+ ProtocolSink_ReportResult
+};
+
+static IInternetProtocolSink protocol_sink = { &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 = file_name + GetCurrentDirectoryA(sizeof(file_name), file_name);
+ *p++ = '\\';
+ strcpy(p, "winetest.mht");
+
+ file = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ ok(file != 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)/sizeof(WCHAR));
+
+ hres = CoCreateInstance(&CLSID_IMimeHtmlProtocol, NULL, CLSCTX_INPROC_SERVER,
&IID_IInternetProtocol, (void**)&protocol);
+ ok(hres == S_OK, "Could not create protocol handler: %08x\n", hres);
+
+ hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolEx,
(void**)&unk);
+ ok(hres == E_NOINTERFACE, "Could get IInternetProtocolEx\n");
+
+ current_binding_test = test;
+ current_binding_protocol = protocol;
+
+ SET_EXPECT(GetBindInfo);
+ SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE);
+ SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE);
+ SET_EXPECT(ReportData);
+ SET_EXPECT(ReportResult);
+ hres = IInternetProtocol_Start(protocol, test_url, &protocol_sink,
&bind_info, 0, 0);
+ ok(hres == 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[] = {
+ {
+ "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.html",
"../..",
+ "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[] =
{'h','t','t','p',':','/','/','t','e','s','t','.','o','r','g',0};
+
+ hres = CoCreateInstance(&CLSID_IMimeHtmlProtocol, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IInternetProtocolInfo, (void**)&protocol_info);
+ ok(hres == S_OK, "Could not create protocol info: %08x\n", hres);
+
+ for(i = 0; i < sizeof(combine_tests)/sizeof(*combine_tests); i++) {
+ base_url = a2w(combine_tests[i].base_url);
+ relative_url = a2w(combine_tests[i].relative_url);
+
+ combined_len = 0xdeadbeef;
+ hres = IInternetProtocolInfo_CombineUrl(protocol_info, base_url, relative_url,
ICU_BROWSER_MODE,
+ combined_url,
sizeof(combined_url)/sizeof(WCHAR), &combined_len, 0);
+ todo_wine_if(combine_tests[i].todo)
+ ok(hres == S_OK, "[%u] CombineUrl failed: %08x\n", i, hres);
+ if(SUCCEEDED(hres)) {
+ exlen = strlen(combine_tests[i].expected_result);
+ ok(combined_len == 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_result);
+
+ combined_len = 0xdeadbeef;
+ hres = IInternetProtocolInfo_CombineUrl(protocol_info, base_url,
relative_url, ICU_BROWSER_MODE,
+ combined_url, exlen,
&combined_len, 0);
+ ok(hres == E_FAIL, "[%u] CombineUrl returned: %08x\n", i, hres);
+ ok(!combined_len, "[%u] combined_len = %u\n", i, combined_len);
+ }
+
+ HeapFree(GetProcessHeap(), 0, base_url);
+ HeapFree(GetProcessHeap(), 0, relative_url);
+ }
+
+ hres = IInternetProtocolInfo_CombineUrl(protocol_info, http_url, http_url,
ICU_BROWSER_MODE,
+ combined_url,
sizeof(combined_url)/sizeof(WCHAR), &combined_len, 0);
+ ok(hres == E_FAIL, "CombineUrl failed: %08x\n", hres);
+
+ IInternetProtocolInfo_Release(protocol_info);
+}
+
+static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID riid, void **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 = {
+ outer_QueryInterface,
+ outer_AddRef,
+ outer_Release
+};
+
+static BOOL broken_mhtml_resolver;
+
+static void test_mhtml_protocol(void)
+{
+ IUnknown outer = { &outer_vtbl };
+ IClassFactory *class_factory;
+ IUnknown *unk, *unk2;
+ unsigned i;
+ HRESULT hres;
+
+ /* test class factory */
+ hres = CoGetClassObject(&CLSID_IMimeHtmlProtocol, CLSCTX_INPROC_SERVER, NULL,
&IID_IUnknown, (void**)&unk);
+ ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres);
+
+ hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo,
(void**)&unk2);
+ ok(hres == E_NOINTERFACE, "IInternetProtocolInfo supported\n");
+
+ hres = IUnknown_QueryInterface(unk, &IID_IClassFactory,
(void**)&class_factory);
+ ok(hres == S_OK, "Could not get IClassFactory iface: %08x\n", hres);
+ IUnknown_Release(unk);
+
+ hres = IClassFactory_CreateInstance(class_factory, &outer, &IID_IUnknown,
(void**)&unk);
+ ok(hres == S_OK, "CreateInstance returned: %08x\n", hres);
+ hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&unk2);
+ ok(hres == S_OK, "Could not get IInternetProtocol iface: %08x\n", hres);
+ IUnknown_Release(unk2);
+ IUnknown_Release(unk);
+
+ hres = IClassFactory_CreateInstance(class_factory, (IUnknown*)0xdeadbeef,
&IID_IInternetProtocol, (void**)&unk2);
+ ok(hres == CLASS_E_NOAGGREGATION, "CreateInstance returned: %08x\n",
hres);
+
+ IClassFactory_Release(class_factory);
+
+ if(!broken_mhtml_resolver)
+ test_mhtml_protocol_info();
+
+ for(i = 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[] = {
+ {"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.winehq.org/index.html?query#hash"},
+ {"../test.mht", "mhtml:../test.mht"}
+ };
+
+ for(i = 0; i < sizeof(tests)/sizeof(*tests); i++) {
+ url = a2w(tests[i].url);
+ hres = CreateURLMoniker(NULL, url, &mon);
+ ok(hres == S_OK, "CreateURLMoniker failed: %08x\n", hres);
+ HeapFree(GetProcessHeap(), 0, url);
+
+ hres = CreateBindCtx(0, &bind_ctx);
+ ok(hres == S_OK, "CreateBindCtx failed: %08x\n", hres);
+
+ hres = MimeOleObjectFromMoniker(0, mon, bind_ctx, &IID_IUnknown,
(void**)&unk, &new_mon);
+ ok(hres == S_OK || broken(!i && hres == INET_E_RESOURCE_NOT_FOUND),
"MimeOleObjectFromMoniker failed: %08x\n", hres);
+ IBindCtx_Release(bind_ctx);
+ if(hres == INET_E_RESOURCE_NOT_FOUND) { /* winxp */
+ win_skip("Broken MHTML behaviour found. Skipping some tests.\n");
+ broken_mhtml_resolver = TRUE;
+ return;
+ }
+
+ hres = IMoniker_GetDisplayName(new_mon, NULL, NULL, &mhtml_url);
+ ok(hres == 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();
}