4 * Copyright 2007 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSUNION
34 #include "wine/test.h"
36 #define DEFINE_EXPECT(func) \
37 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
39 #define SET_EXPECT(func) \
40 expect_ ## func = TRUE
42 #define CHECK_EXPECT(func) \
44 ok(expect_ ##func, "unexpected call " #func "\n"); \
45 expect_ ## func = FALSE; \
46 called_ ## func = TRUE; \
49 #define CHECK_EXPECT2(func) \
51 ok(expect_ ##func, "unexpected call " #func "\n"); \
52 called_ ## func = TRUE; \
55 #define CHECK_CALLED(func) \
57 ok(called_ ## func, "expected " #func "\n"); \
58 expect_ ## func = called_ ## func = FALSE; \
61 DEFINE_EXPECT(Stream_Read
);
62 DEFINE_EXPECT(Stream_Stat
);
63 DEFINE_EXPECT(Stream_Seek
);
64 DEFINE_EXPECT(Stream_Seek_END
);
65 DEFINE_EXPECT(GetBindInfo
);
66 DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
67 DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
68 DEFINE_EXPECT(ReportData
);
69 DEFINE_EXPECT(ReportResult
);
71 static const char msg1
[] =
72 "MIME-Version: 1.0\r\n"
73 "Content-Type: multipart/mixed;\r\n"
74 " boundary=\"------------1.5.0.6\";\r\n"
75 " stuff=\"du;nno\";\r\n"
76 " morestuff=\"so\\\\me\\\"thing\\\"\"\r\n"
78 "From: Huw Davies <huw@codeweavers.com>\r\n"
79 "From: Me <xxx@codeweavers.com>\r\n"
80 "To: wine-patches <wine-patches@winehq.org>\r\n"
81 "Cc: Huw Davies <huw@codeweavers.com>,\r\n"
82 " \"Fred Bloggs\" <fred@bloggs.com>\r\n"
86 "This is a multi-part message in MIME format.\r\n"
87 "--------------1.5.0.6\r\n"
88 "Content-Type: text/plain; format=fixed; charset=UTF-8\r\n"
89 "Content-Transfer-Encoding: 8bit\r\n"
92 "--------------1.5.0.6\r\n"
93 "Content-Type: text/plain; charset=\"us-ascii\"\r\n"
94 "Content-Transfer-Encoding: 7bit\r\n"
97 "--------------1.5.0.6--\r\n";
99 static const char mhtml_page1
[] =
100 "MIME-Version: 1.0\r\n"
101 "Content-Type: multipart/related; type:=\"text/html\"; boundary=\"----=_NextPart_000_00\"\r\n"
103 "------=_NextPart_000_00\r\n"
104 "Content-Type: text/html; charset=\"Windows-1252\"\r\n"
105 "Content-Transfer-Encoding: quoted-printable\r\n"
108 "------=_NextPart_000_00\r\n"
109 "Content-Type: Image/Jpeg\r\n"
110 "Content-Transfer-Encoding: base64\r\n"
111 "Content-Location: http://winehq.org/mhtmltest.html\r\n"
112 "\r\n\t\t\t\tVGVzdA==\r\n\r\n"
113 "------=_NextPart_000_00--";
115 static void test_CreateVirtualStream(void)
120 hr
= MimeOleCreateVirtualStream(&pstm
);
121 ok(hr
== S_OK
, "ret %08x\n", hr
);
123 IStream_Release(pstm
);
126 static void test_CreateSecurity(void)
131 hr
= MimeOleCreateSecurity(&sec
);
132 ok(hr
== S_OK
, "ret %08x\n", hr
);
134 IMimeSecurity_Release(sec
);
137 static IStream
*create_stream_from_string(const char *data
)
143 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
);
144 ok(hr
== S_OK
, "ret %08x\n", hr
);
146 hr
= IStream_Write(stream
, data
, strlen(data
), NULL
);
147 ok(hr
== S_OK
, "Write failed: %08x\n", hr
);
150 hr
= IStream_Seek(stream
, off
, STREAM_SEEK_SET
, NULL
);
151 ok(hr
== S_OK
, "Seek failed: %08x\n", hr
);
156 #define test_current_encoding(a,b) _test_current_encoding(__LINE__,a,b)
157 static void _test_current_encoding(unsigned line
, IMimeBody
*mime_body
, ENCODINGTYPE encoding
)
159 ENCODINGTYPE current_encoding
;
162 hres
= IMimeBody_GetCurrentEncoding(mime_body
, ¤t_encoding
);
163 ok_(__FILE__
,line
)(hres
== S_OK
, "GetCurrentEncoding failed: %08x\n", hres
);
164 ok_(__FILE__
,line
)(current_encoding
== encoding
, "encoding = %d, expected %d\n", current_encoding
, encoding
);
167 static void test_CreateBody(void)
171 HBODY handle
= (void *)0xdeadbeef;
175 ULONG count
, found_param
, i
;
176 MIMEPARAMINFO
*param_info
;
177 IMimeAllocator
*alloc
;
181 hr
= CoCreateInstance(&CLSID_IMimeBody
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMimeBody
, (void**)&body
);
182 ok(hr
== S_OK
, "ret %08x\n", hr
);
184 hr
= IMimeBody_GetClassID(body
, NULL
);
185 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
187 hr
= IMimeBody_GetClassID(body
, &clsid
);
188 ok(hr
== S_OK
, "ret %08x\n", hr
);
189 ok(IsEqualGUID(&clsid
, &IID_IMimeBody
), "got %s\n", wine_dbgstr_guid(&clsid
));
191 hr
= IMimeBody_GetHandle(body
, &handle
);
192 ok(hr
== MIME_E_NO_DATA
, "ret %08x\n", hr
);
193 ok(handle
== NULL
, "handle %p\n", handle
);
195 in
= create_stream_from_string(msg1
);
197 /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
198 hr
= IMimeBody_InitNew(body
);
199 ok(hr
== S_OK
, "ret %08x\n", hr
);
201 test_current_encoding(body
, IET_7BIT
);
203 hr
= IMimeBody_Load(body
, in
);
204 ok(hr
== S_OK
, "ret %08x\n", hr
);
206 IStream_Seek(in
, off
, STREAM_SEEK_CUR
, &pos
);
207 ok(pos
.u
.LowPart
== 359, "pos %u\n", pos
.u
.LowPart
);
209 hr
= IMimeBody_IsContentType(body
, "multipart", "mixed");
210 ok(hr
== S_OK
, "ret %08x\n", hr
);
211 hr
= IMimeBody_IsContentType(body
, "text", "plain");
212 ok(hr
== S_FALSE
, "ret %08x\n", hr
);
213 hr
= IMimeBody_IsContentType(body
, NULL
, "mixed");
214 ok(hr
== S_OK
, "ret %08x\n", hr
);
215 hr
= IMimeBody_IsType(body
, IBT_EMPTY
);
216 ok(hr
== S_OK
, "got %08x\n", hr
);
218 hr
= IMimeBody_SetData(body
, IET_8BIT
, "text", "plain", &IID_IStream
, in
);
219 ok(hr
== S_OK
, "ret %08x\n", hr
);
220 hr
= IMimeBody_IsContentType(body
, "text", "plain");
222 ok(hr
== S_OK
, "ret %08x\n", hr
);
223 test_current_encoding(body
, IET_8BIT
);
225 memset(&offsets
, 0xcc, sizeof(offsets
));
226 hr
= IMimeBody_GetOffsets(body
, &offsets
);
227 ok(hr
== MIME_E_NO_DATA
, "ret %08x\n", hr
);
228 ok(offsets
.cbBoundaryStart
== 0, "got %d\n", offsets
.cbBoundaryStart
);
229 ok(offsets
.cbHeaderStart
== 0, "got %d\n", offsets
.cbHeaderStart
);
230 ok(offsets
.cbBodyStart
== 0, "got %d\n", offsets
.cbBodyStart
);
231 ok(offsets
.cbBodyEnd
== 0, "got %d\n", offsets
.cbBodyEnd
);
233 hr
= IMimeBody_IsType(body
, IBT_EMPTY
);
234 ok(hr
== S_FALSE
, "got %08x\n", hr
);
236 hr
= MimeOleGetAllocator(&alloc
);
237 ok(hr
== S_OK
, "ret %08x\n", hr
);
239 hr
= IMimeBody_GetParameters(body
, "nothere", &count
, ¶m_info
);
240 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
241 ok(count
== 0, "got %d\n", count
);
242 ok(!param_info
, "got %p\n", param_info
);
244 hr
= IMimeBody_GetParameters(body
, "bar", &count
, ¶m_info
);
245 ok(hr
== S_OK
, "ret %08x\n", hr
);
246 ok(count
== 0, "got %d\n", count
);
247 ok(!param_info
, "got %p\n", param_info
);
249 hr
= IMimeBody_GetParameters(body
, "Content-Type", &count
, ¶m_info
);
250 ok(hr
== S_OK
, "ret %08x\n", hr
);
251 todo_wine
/* native adds a charset parameter */
252 ok(count
== 4, "got %d\n", count
);
253 ok(param_info
!= NULL
, "got %p\n", param_info
);
256 for(i
= 0; i
< count
; i
++)
258 if(!strcmp(param_info
[i
].pszName
, "morestuff"))
261 ok(!strcmp(param_info
[i
].pszData
, "so\\me\"thing\""),
262 "got %s\n", param_info
[i
].pszData
);
264 else if(!strcmp(param_info
[i
].pszName
, "stuff"))
267 ok(!strcmp(param_info
[i
].pszData
, "du;nno"),
268 "got %s\n", param_info
[i
].pszData
);
271 ok(found_param
== 2, "matched %d params\n", found_param
);
273 hr
= IMimeAllocator_FreeParamInfoArray(alloc
, count
, param_info
, TRUE
);
274 ok(hr
== S_OK
, "ret %08x\n", hr
);
275 IMimeAllocator_Release(alloc
);
278 IMimeBody_Release(body
);
282 IStream IStream_iface
;
287 static inline TestStream
*impl_from_IStream(IStream
*iface
)
289 return CONTAINING_RECORD(iface
, TestStream
, IStream_iface
);
292 static HRESULT WINAPI
Stream_QueryInterface(IStream
*iface
, REFIID riid
, void **ppv
)
294 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_ISequentialStream
, riid
) || IsEqualGUID(&IID_IStream
, riid
)) {
299 ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid
));
301 return E_NOINTERFACE
;
304 static ULONG WINAPI
Stream_AddRef(IStream
*iface
)
306 TestStream
*This
= impl_from_IStream(iface
);
307 return InterlockedIncrement(&This
->ref
);
310 static ULONG WINAPI
Stream_Release(IStream
*iface
)
312 TestStream
*This
= impl_from_IStream(iface
);
313 ULONG ref
= InterlockedDecrement(&This
->ref
);
316 HeapFree(GetProcessHeap(), 0, This
);
321 static HRESULT WINAPI
Stream_Read(IStream
*iface
, void *pv
, ULONG cb
, ULONG
*pcbRead
)
323 TestStream
*This
= impl_from_IStream(iface
);
327 CHECK_EXPECT(Stream_Read
);
329 for(i
= 0; i
< cb
; i
++)
330 output
[i
] = '0' + This
->pos
++;
335 static HRESULT WINAPI
Stream_Write(IStream
*iface
, const void *pv
, ULONG cb
, ULONG
*pcbWritten
)
337 ok(0, "unexpected call\n");
341 static DWORD expect_seek_pos
;
343 static HRESULT WINAPI
Stream_Seek(IStream
*iface
, LARGE_INTEGER dlibMove
, DWORD dwOrigin
,
344 ULARGE_INTEGER
*plibNewPosition
)
346 TestStream
*This
= impl_from_IStream(iface
);
348 if(dwOrigin
== STREAM_SEEK_END
) {
349 CHECK_EXPECT(Stream_Seek_END
);
350 ok(dlibMove
.QuadPart
== expect_seek_pos
, "unexpected seek pos %u\n", dlibMove
.u
.LowPart
);
352 plibNewPosition
->QuadPart
= 10;
356 CHECK_EXPECT(Stream_Seek
);
358 ok(dlibMove
.QuadPart
== expect_seek_pos
, "unexpected seek pos %u\n", dlibMove
.u
.LowPart
);
359 ok(dwOrigin
== STREAM_SEEK_SET
, "dwOrigin = %d\n", dwOrigin
);
360 This
->pos
= dlibMove
.QuadPart
;
362 plibNewPosition
->QuadPart
= This
->pos
;
366 static HRESULT WINAPI
Stream_SetSize(IStream
*iface
, ULARGE_INTEGER libNewSize
)
368 ok(0, "unexpected call\n");
372 static HRESULT WINAPI
Stream_CopyTo(IStream
*iface
, IStream
*pstm
, ULARGE_INTEGER cb
,
373 ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
375 ok(0, "unexpected call\n");
379 static HRESULT WINAPI
Stream_Commit(IStream
*iface
, DWORD grfCommitFlags
)
381 ok(0, "unexpected call\n");
385 static HRESULT WINAPI
Stream_Revert(IStream
*iface
)
387 ok(0, "unexpected call\n");
391 static HRESULT WINAPI
Stream_LockRegion(IStream
*iface
, ULARGE_INTEGER libOffset
,
392 ULARGE_INTEGER cb
, DWORD dwLockType
)
394 ok(0, "unexpected call\n");
398 static HRESULT WINAPI
Stream_UnlockRegion(IStream
*iface
,
399 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
401 ok(0, "unexpected call\n");
405 static HRESULT WINAPI
Stream_Stat(IStream
*iface
, STATSTG
*pstatstg
, DWORD dwStatFlag
)
407 CHECK_EXPECT(Stream_Stat
);
408 ok(dwStatFlag
== STATFLAG_NONAME
, "dwStatFlag = %x\n", dwStatFlag
);
412 static HRESULT WINAPI
Stream_Clone(IStream
*iface
, IStream
**ppstm
)
414 ok(0, "unexpected call\n");
418 static const IStreamVtbl StreamVtbl
= {
419 Stream_QueryInterface
,
435 static IStream
*create_test_stream(void)
438 stream
= HeapAlloc(GetProcessHeap(), 0, sizeof(*stream
));
439 stream
->IStream_iface
.lpVtbl
= &StreamVtbl
;
442 return &stream
->IStream_iface
;
445 #define test_stream_read(a,b,c,d) _test_stream_read(__LINE__,a,b,c,d)
446 static void _test_stream_read(unsigned line
, IStream
*stream
, HRESULT exhres
, const char *exdata
, unsigned read_size
)
448 ULONG read
= 0xdeadbeed, exread
= strlen(exdata
);
453 read_size
= sizeof(buf
)-1;
455 hres
= IStream_Read(stream
, buf
, read_size
, &read
);
456 ok_(__FILE__
,line
)(hres
== exhres
, "Read returned %08x, expected %08x\n", hres
, exhres
);
457 ok_(__FILE__
,line
)(read
== exread
, "unexpected read size %u, expected %u\n", read
, exread
);
459 ok_(__FILE__
,line
)(read
== exread
&& !memcmp(buf
, exdata
, read
), "unexpected data %s\n", buf
);
462 static void test_SetData(void)
464 IStream
*stream
, *stream2
, *test_stream
;
468 hr
= CoCreateInstance(&CLSID_IMimeBody
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMimeBody
, (void**)&body
);
469 ok(hr
== S_OK
, "ret %08x\n", hr
);
471 /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
472 hr
= IMimeBody_InitNew(body
);
473 ok(hr
== S_OK
, "ret %08x\n", hr
);
475 stream
= create_stream_from_string(msg1
);
476 hr
= IMimeBody_Load(body
, stream
);
477 ok(hr
== S_OK
, "ret %08x\n", hr
);
478 IStream_Release(stream
);
480 test_stream
= create_test_stream();
481 hr
= IMimeBody_SetData(body
, IET_BINARY
, "text", "plain", &IID_IStream
, test_stream
);
483 ok(hr
== S_OK
, "ret %08x\n", hr
);
484 hr
= IMimeBody_IsContentType(body
, "text", "plain");
486 ok(hr
== S_OK
, "ret %08x\n", hr
);
488 test_current_encoding(body
, IET_BINARY
);
490 SET_EXPECT(Stream_Stat
);
491 SET_EXPECT(Stream_Seek_END
);
492 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
493 CHECK_CALLED(Stream_Stat
);
494 CHECK_CALLED(Stream_Seek_END
);
495 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
496 ok(stream
!= test_stream
, "unexpected stream\n");
498 SET_EXPECT(Stream_Seek
);
499 SET_EXPECT(Stream_Read
);
500 test_stream_read(stream
, S_OK
, "012", 3);
501 CHECK_CALLED(Stream_Seek
);
502 CHECK_CALLED(Stream_Read
);
504 SET_EXPECT(Stream_Stat
);
505 SET_EXPECT(Stream_Seek_END
);
506 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream2
);
507 CHECK_CALLED(Stream_Stat
);
508 CHECK_CALLED(Stream_Seek_END
);
509 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
510 ok(stream2
!= stream
, "unexpected stream\n");
512 SET_EXPECT(Stream_Seek
);
513 SET_EXPECT(Stream_Read
);
514 test_stream_read(stream2
, S_OK
, "01", 2);
515 CHECK_CALLED(Stream_Seek
);
516 CHECK_CALLED(Stream_Read
);
519 SET_EXPECT(Stream_Seek
);
520 SET_EXPECT(Stream_Read
);
521 test_stream_read(stream
, S_OK
, "345", 3);
522 CHECK_CALLED(Stream_Seek
);
523 CHECK_CALLED(Stream_Read
);
525 IStream_Release(stream
);
526 IStream_Release(stream2
);
527 IStream_Release(test_stream
);
529 stream
= create_stream_from_string(" \t\r\n|}~YWJj ZGV|}~mZw== \t"); /* "abcdefg" in base64 obscured by invalid chars */
530 hr
= IMimeBody_SetData(body
, IET_BASE64
, "text", "plain", &IID_IStream
, stream
);
531 IStream_Release(stream
);
532 ok(hr
== S_OK
, "SetData failed: %08x\n", hr
);
534 test_current_encoding(body
, IET_BASE64
);
536 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
537 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
539 test_stream_read(stream
, S_OK
, "abc", 3);
540 test_stream_read(stream
, S_OK
, "defg", -1);
542 IStream_Release(stream
);
544 hr
= IMimeBody_GetData(body
, IET_BASE64
, &stream
);
545 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
547 test_stream_read(stream
, S_OK
, " \t\r", 3);
548 IStream_Release(stream
);
550 stream
= create_stream_from_string(" =3d=3D\"one\" \t=\r\ntw= o=\nx3\n=34\r\n5");
551 hr
= IMimeBody_SetData(body
, IET_QP
, "text", "plain", &IID_IStream
, stream
);
552 IStream_Release(stream
);
553 ok(hr
== S_OK
, "SetData failed: %08x\n", hr
);
555 test_current_encoding(body
, IET_QP
);
557 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
558 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
560 test_stream_read(stream
, S_OK
, " ==\"one\" \ttw=o=3\n4\r\n5", -1);
562 IStream_Release(stream
);
564 IMimeBody_Release(body
);
567 static void test_Allocator(void)
570 IMimeAllocator
*alloc
;
572 hr
= MimeOleGetAllocator(&alloc
);
573 ok(hr
== S_OK
, "ret %08x\n", hr
);
574 IMimeAllocator_Release(alloc
);
577 static void test_CreateMessage(void)
587 FINDBODY find_struct
;
591 char text
[] = "text";
594 static const char att_pritype
[] = "att:pri-content-type";
596 hr
= MimeOleCreateMessage(NULL
, &msg
);
597 ok(hr
== S_OK
, "ret %08x\n", hr
);
599 stream
= create_stream_from_string(msg1
);
601 hr
= IMimeMessage_Load(msg
, stream
);
602 ok(hr
== S_OK
, "ret %08x\n", hr
);
604 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, TRUE
, &count
);
605 ok(hr
== S_OK
, "ret %08x\n", hr
);
606 ok(count
== 3, "got %d\n", count
);
608 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, FALSE
, &count
);
609 ok(hr
== S_OK
, "ret %08x\n", hr
);
610 ok(count
== 3, "got %d\n", count
);
612 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
613 ok(hr
== S_OK
, "ret %08x\n", hr
);
614 hr
= IMimeBody_GetOffsets(body
, &offsets
);
615 ok(hr
== S_OK
, "ret %08x\n", hr
);
616 ok(offsets
.cbBoundaryStart
== 0, "got %d\n", offsets
.cbBoundaryStart
);
617 ok(offsets
.cbHeaderStart
== 0, "got %d\n", offsets
.cbHeaderStart
);
618 ok(offsets
.cbBodyStart
== 359, "got %d\n", offsets
.cbBodyStart
);
619 ok(offsets
.cbBodyEnd
== 666, "got %d\n", offsets
.cbBodyEnd
);
620 IMimeBody_Release(body
);
622 hr
= IMimeMessage_GetBody(msg
, IBL_ROOT
, NULL
, &hbody
);
623 ok(hr
== S_OK
, "ret %08x\n", hr
);
625 hr
= IMimeBody_GetHandle(body
, NULL
);
626 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
628 hr
= IMimeBody_GetHandle(body
, &handle
);
629 ok(hr
== S_OK
, "ret %08x\n", hr
);
630 ok(handle
!= NULL
, "handle %p\n", handle
);
632 hr
= IMimeMessage_GetBody(msg
, IBL_PARENT
, hbody
, NULL
);
633 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
635 hbody2
= (HBODY
)0xdeadbeef;
636 hr
= IMimeMessage_GetBody(msg
, IBL_PARENT
, hbody
, &hbody2
);
637 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
638 ok(hbody2
== NULL
, "hbody2 %p\n", hbody2
);
640 PropVariantInit(&prop
);
641 hr
= IMimeMessage_GetBodyProp(msg
, hbody
, att_pritype
, 0, &prop
);
642 ok(hr
== S_OK
, "ret %08x\n", hr
);
643 ok(prop
.vt
== VT_LPSTR
, "vt %08x\n", prop
.vt
);
644 ok(!strcasecmp(prop
.pszVal
, "multipart"), "got %s\n", prop
.pszVal
);
645 PropVariantClear(&prop
);
647 hr
= IMimeMessage_GetBody(msg
, IBL_FIRST
, hbody
, &hbody
);
648 ok(hr
== S_OK
, "ret %08x\n", hr
);
649 hr
= IMimeMessage_BindToObject(msg
, hbody
, &IID_IMimeBody
, (void**)&body
);
650 ok(hr
== S_OK
, "ret %08x\n", hr
);
652 hr
= IMimeBody_GetHandle(body
, &handle
);
653 ok(hr
== S_OK
, "ret %08x\n", hr
);
654 ok(handle
== hbody
, "handle %p\n", handle
);
656 hr
= IMimeBody_GetOffsets(body
, &offsets
);
657 ok(hr
== S_OK
, "ret %08x\n", hr
);
658 ok(offsets
.cbBoundaryStart
== 405, "got %d\n", offsets
.cbBoundaryStart
);
659 ok(offsets
.cbHeaderStart
== 428, "got %d\n", offsets
.cbHeaderStart
);
660 ok(offsets
.cbBodyStart
== 518, "got %d\n", offsets
.cbBodyStart
);
661 ok(offsets
.cbBodyEnd
== 523, "got %d\n", offsets
.cbBodyEnd
);
663 hr
= IMimeBody_GetCharset(body
, &hcs
);
664 ok(hr
== S_OK
, "ret %08x\n", hr
);
667 ok(hcs
!= NULL
, "Expected non-NULL charset\n");
670 IMimeBody_Release(body
);
672 hr
= IMimeMessage_GetBody(msg
, IBL_NEXT
, hbody
, &hbody
);
673 ok(hr
== S_OK
, "ret %08x\n", hr
);
674 hr
= IMimeMessage_BindToObject(msg
, hbody
, &IID_IMimeBody
, (void**)&body
);
675 ok(hr
== S_OK
, "ret %08x\n", hr
);
677 hr
= IMimeBody_GetHandle(body
, &handle
);
678 ok(hr
== S_OK
, "ret %08x\n", hr
);
679 ok(handle
== hbody
, "handle %p\n", handle
);
681 hr
= IMimeBody_GetOffsets(body
, &offsets
);
682 ok(hr
== S_OK
, "ret %08x\n", hr
);
683 ok(offsets
.cbBoundaryStart
== 525, "got %d\n", offsets
.cbBoundaryStart
);
684 ok(offsets
.cbHeaderStart
== 548, "got %d\n", offsets
.cbHeaderStart
);
685 ok(offsets
.cbBodyStart
== 629, "got %d\n", offsets
.cbBodyStart
);
686 ok(offsets
.cbBodyEnd
== 639, "got %d\n", offsets
.cbBodyEnd
);
687 IMimeBody_Release(body
);
689 find_struct
.pszPriType
= text
;
690 find_struct
.pszSubType
= NULL
;
692 hr
= IMimeMessage_FindFirst(msg
, &find_struct
, &hbody
);
693 ok(hr
== S_OK
, "ret %08x\n", hr
);
695 hr
= IMimeMessage_FindNext(msg
, &find_struct
, &hbody
);
696 ok(hr
== S_OK
, "ret %08x\n", hr
);
698 hr
= IMimeMessage_FindNext(msg
, &find_struct
, &hbody
);
699 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
701 hr
= IMimeMessage_GetAttachments(msg
, &count
, &body_list
);
702 ok(hr
== S_OK
, "ret %08x\n", hr
);
703 ok(count
== 2, "got %d\n", count
);
706 IMimeBody
*attachment
;
709 PropVariantInit(&prop
);
711 hr
= IMimeMessage_BindToObject(msg
, body_list
[0], &IID_IMimeBody
, (void**)&attachment
);
712 ok(hr
== S_OK
, "ret %08x\n", hr
);
714 hr
= IMimeBody_IsContentType(attachment
, "multipart", NULL
);
715 ok(hr
== S_FALSE
, "ret %08x\n", hr
);
717 test_current_encoding(attachment
, IET_8BIT
);
720 hr
= IMimeBody_GetProp(attachment
, "Content-Transfer-Encoding", 0, &prop
);
721 ok(hr
== S_OK
, "ret %08x\n", hr
);
723 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
724 ok(!strcmp(prop
.pszVal
, "8bit"), "got %s\n", prop
.pszVal
);
725 PropVariantClear(&prop
);
727 hr
= IMimeBody_IsType(attachment
, IBT_ATTACHMENT
);
728 todo_wine
ok(hr
== S_FALSE
, "ret %08x\n", hr
);
730 IMimeBody_Release(attachment
);
732 hr
= IMimeMessage_BindToObject(msg
, body_list
[1], &IID_IMimeBody
, (void**)&attachment
);
733 ok(hr
== S_OK
, "ret %08x\n", hr
);
735 hr
= IMimeBody_IsContentType(attachment
, "multipart", NULL
);
736 ok(hr
== S_FALSE
, "ret %08x\n", hr
);
738 test_current_encoding(attachment
, IET_7BIT
);
741 hr
= IMimeBody_GetProp(attachment
, "Content-Transfer-Encoding", 0, &prop
);
742 ok(hr
== S_OK
, "ret %08x\n", hr
);
743 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
744 ok(!strcmp(prop
.pszVal
, "7bit"), "got %s\n", prop
.pszVal
);
745 PropVariantClear(&prop
);
747 hr
= IMimeBody_IsType(attachment
, IBT_ATTACHMENT
);
748 ok(hr
== S_OK
, "ret %08x\n", hr
);
750 IMimeBody_Release(attachment
);
752 CoTaskMemFree(body_list
);
754 hr
= IMimeBody_GetCharset(body
, &hcs
);
755 ok(hr
== S_OK
, "ret %08x\n", hr
);
758 ok(hcs
!= NULL
, "Expected non-NULL charset\n");
761 IMimeMessage_Release(msg
);
763 ref
= IStream_AddRef(stream
);
765 broken(ref
== 1), /* win95 */
767 IStream_Release(stream
);
769 IStream_Release(stream
);
772 static void test_mhtml_message(void)
774 IMimeMessage
*mime_message
;
775 IMimeBody
*mime_body
;
781 hres
= MimeOleCreateMessage(NULL
, &mime_message
);
782 ok(hres
== S_OK
, "MimeOleCreateMessage failed: %08x\n", hres
);
784 stream
= create_stream_from_string(mhtml_page1
);
785 hres
= IMimeMessage_Load(mime_message
, stream
);
786 IStream_Release(stream
);
787 ok(hres
== S_OK
, "Load failed: %08x\n", hres
);
789 hres
= IMimeMessage_CountBodies(mime_message
, HBODY_ROOT
, TRUE
, &count
);
790 ok(hres
== S_OK
, "CountBodies failed: %08x\n", hres
);
791 ok(count
== 3, "got %d\n", count
);
793 hres
= IMimeMessage_GetAttachments(mime_message
, &count
, &body_list
);
794 ok(hres
== S_OK
, "GetAttachments failed: %08x\n", hres
);
795 ok(count
== 2, "count = %u\n", count
);
797 hres
= IMimeMessage_BindToObject(mime_message
, body_list
[0], &IID_IMimeBody
, (void**)&mime_body
);
798 ok(hres
== S_OK
, "BindToObject failed: %08x\n", hres
);
800 hres
= IMimeBody_GetData(mime_body
, IET_BINARY
, &stream
);
801 ok(hres
== S_OK
, "GetData failed: %08x\n", hres
);
802 test_stream_read(stream
, S_OK
, "<HTML></HTML>", -1);
803 IStream_Release(stream
);
805 test_current_encoding(mime_body
, IET_QP
);
807 IMimeBody_Release(mime_body
);
809 hres
= IMimeMessage_BindToObject(mime_message
, body_list
[1], &IID_IMimeBody
, (void**)&mime_body
);
810 ok(hres
== S_OK
, "BindToObject failed: %08x\n", hres
);
812 test_current_encoding(mime_body
, IET_BASE64
);
814 hres
= IMimeBody_GetData(mime_body
, IET_BINARY
, &stream
);
815 ok(hres
== S_OK
, "GetData failed: %08x\n", hres
);
816 test_stream_read(stream
, S_OK
, "Test", -1);
817 IStream_Release(stream
);
819 IMimeBody_Release(mime_body
);
821 CoTaskMemFree(body_list
);
823 IMimeMessage_Release(mime_message
);
826 static void test_MessageSetProp(void)
828 static const char topic
[] = "wine topic";
834 hr
= MimeOleCreateMessage(NULL
, &msg
);
835 ok(hr
== S_OK
, "ret %08x\n", hr
);
837 PropVariantInit(&prop
);
839 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
840 ok(hr
== S_OK
, "ret %08x\n", hr
);
842 hr
= IMimeBody_SetProp(body
, NULL
, 0, &prop
);
843 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
845 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, NULL
);
846 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
849 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
850 strcpy(prop
.pszVal
, topic
);
851 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, &prop
);
852 ok(hr
== S_OK
, "ret %08x\n", hr
);
853 PropVariantClear(&prop
);
855 hr
= IMimeBody_GetProp(body
, NULL
, 0, &prop
);
856 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
858 hr
= IMimeBody_GetProp(body
, "Thread-Topic", 0, NULL
);
859 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
861 hr
= IMimeBody_GetProp(body
, "Wine-Topic", 0, &prop
);
862 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
865 hr
= IMimeBody_GetProp(body
, "Thread-Topic", 0, &prop
);
866 ok(hr
== S_OK
, "ret %08x\n", hr
);
869 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
870 ok(!strcmp(prop
.pszVal
, topic
), "got %s\n", prop
.pszVal
);
871 PropVariantClear(&prop
);
875 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
876 strcpy(prop
.pszVal
, topic
);
877 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
878 ok(hr
== S_OK
, "ret %08x\n", hr
);
879 PropVariantClear(&prop
);
882 hr
= IMimeBody_GetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
883 ok(hr
== S_OK
, "ret %08x\n", hr
);
886 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
887 ok(!strcmp(prop
.pszVal
, topic
), "got %s\n", prop
.pszVal
);
888 PropVariantClear(&prop
);
891 /* Using the name or PID returns the same result. */
893 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
894 ok(hr
== S_OK
, "ret %08x\n", hr
);
897 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
898 ok(!strcmp(prop
.pszVal
, topic
), "got %s\n", prop
.pszVal
);
899 PropVariantClear(&prop
);
903 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
904 ok(hr
== S_OK
, "ret %08x\n", hr
);
907 ok(prop
.vt
== VT_LPWSTR
, "type %d\n", prop
.vt
);
908 ok(!lstrcmpW(prop
.pwszVal
, L
"wine topic"), "got %s\n", wine_dbgstr_w(prop
.pwszVal
));
909 PropVariantClear(&prop
);
913 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
914 strcpy(prop
.pszVal
, topic
);
915 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_TO
), 0, &prop
);
916 ok(hr
== S_OK
, "ret %08x\n", hr
);
917 PropVariantClear(&prop
);
919 /* Out of Range PID */
921 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
922 strcpy(prop
.pszVal
, topic
);
923 hr
= IMimeBody_SetProp(body
, PIDTOSTR(124), 0, &prop
);
924 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
925 PropVariantClear(&prop
);
927 IMimeBody_Release(body
);
928 IMimeMessage_Release(msg
);
931 static void test_MessageGetPropInfo(void)
933 static const char topic
[] = "wine topic";
934 static const char subject
[] = "wine testing";
941 hr
= MimeOleCreateMessage(NULL
, &msg
);
942 ok(hr
== S_OK
, "ret %08x\n", hr
);
944 PropVariantInit(&prop
);
946 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
947 ok(hr
== S_OK
, "ret %08x\n", hr
);
950 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
951 strcpy(prop
.pszVal
, topic
);
952 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, &prop
);
953 ok(hr
== S_OK
, "ret %08x\n", hr
);
954 PropVariantClear(&prop
);
957 prop
.pszVal
= CoTaskMemAlloc(strlen(subject
)+1);
958 strcpy(prop
.pszVal
, subject
);
959 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
960 ok(hr
== S_OK
, "ret %08x\n", hr
);
961 PropVariantClear(&prop
);
963 memset(&info
, 0, sizeof(info
));
964 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
965 hr
= IMimeBody_GetPropInfo(body
, NULL
, &info
);
966 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
968 memset(&info
, 0, sizeof(info
));
969 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
970 hr
= IMimeBody_GetPropInfo(body
, "Subject", NULL
);
971 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
973 memset(&info
, 0xfe, sizeof(info
));
974 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
975 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
976 ok(hr
== S_OK
, "ret %08x\n", hr
);
979 ok(info
.dwMask
& (PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
), "Invalid mask 0x%08x\n", info
.dwFlags
);
980 todo_wine
ok(info
.dwFlags
& 0x10000000, "Invalid flags 0x%08x\n", info
.dwFlags
);
981 ok(info
.ietEncoding
== 0, "Invalid encoding %d\n", info
.ietEncoding
);
982 ok(info
.dwPropId
== PID_HDR_SUBJECT
, "Invalid propid %d\n", info
.dwPropId
);
983 ok(info
.cValues
== 0xfefefefe, "Invalid cValues %d\n", info
.cValues
);
986 memset(&info
, 0xfe, sizeof(info
));
988 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
989 ok(hr
== S_OK
, "ret %08x\n", hr
);
992 ok(info
.dwMask
== 0, "Invalid mask 0x%08x\n", info
.dwFlags
);
993 ok(info
.dwFlags
== 0xfefefefe, "Invalid flags 0x%08x\n", info
.dwFlags
);
994 ok(info
.ietEncoding
== -16843010, "Invalid encoding %d\n", info
.ietEncoding
);
995 ok(info
.dwPropId
== -16843010, "Invalid propid %d\n", info
.dwPropId
);
998 memset(&info
, 0xfe, sizeof(info
));
1000 info
.dwPropId
= 1024;
1001 info
.ietEncoding
= 99;
1002 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
1003 ok(hr
== S_OK
, "ret %08x\n", hr
);
1006 ok(info
.dwMask
== 0, "Invalid mask 0x%08x\n", info
.dwFlags
);
1007 ok(info
.dwFlags
== 0xfefefefe, "Invalid flags 0x%08x\n", info
.dwFlags
);
1008 ok(info
.ietEncoding
== 99, "Invalid encoding %d\n", info
.ietEncoding
);
1009 ok(info
.dwPropId
== 1024, "Invalid propid %d\n", info
.dwPropId
);
1012 memset(&info
, 0, sizeof(info
));
1013 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
1014 hr
= IMimeBody_GetPropInfo(body
, "Invalid Property", &info
);
1015 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1017 IMimeBody_Release(body
);
1018 IMimeMessage_Release(msg
);
1021 static void test_MessageOptions(void)
1023 static const char string
[] = "XXXXX";
1024 static const char zero
[] = "0";
1029 hr
= MimeOleCreateMessage(NULL
, &msg
);
1030 ok(hr
== S_OK
, "ret %08x\n", hr
);
1032 PropVariantInit(&prop
);
1035 prop
.boolVal
= TRUE
;
1036 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1037 ok(hr
== S_OK
, "ret %08x\n", hr
);
1038 PropVariantClear(&prop
);
1040 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1041 todo_wine
ok(hr
== S_OK
, "ret %08x\n", hr
);
1042 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1043 todo_wine
ok(prop
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.boolVal
);
1044 PropVariantClear(&prop
);
1047 prop
.pszVal
= CoTaskMemAlloc(strlen(string
)+1);
1048 strcpy(prop
.pszVal
, string
);
1049 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1050 ok(hr
== S_OK
, "ret %08x\n", hr
);
1051 PropVariantClear(&prop
);
1053 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1054 todo_wine
ok(hr
== S_OK
, "ret %08x\n", hr
);
1055 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1056 todo_wine
ok(prop
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.boolVal
);
1057 PropVariantClear(&prop
);
1059 /* Invalid property type doesn't change the value */
1061 prop
.pszVal
= CoTaskMemAlloc(strlen(zero
)+1);
1062 strcpy(prop
.pszVal
, zero
);
1063 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1064 ok(hr
== S_OK
, "ret %08x\n", hr
);
1065 PropVariantClear(&prop
);
1067 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1068 todo_wine
ok(hr
== S_OK
, "ret %08x\n", hr
);
1069 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1070 todo_wine
ok(prop
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.boolVal
);
1071 PropVariantClear(&prop
);
1075 prop
.boolVal
= TRUE
;
1076 hr
= IMimeMessage_SetOption(msg
, 0xff00000a, &prop
);
1077 ok(hr
== MIME_E_INVALID_OPTION_ID
, "ret %08x\n", hr
);
1078 PropVariantClear(&prop
);
1080 /* Out of range before type. */
1083 hr
= IMimeMessage_SetOption(msg
, 0xff00000a, &prop
);
1084 ok(hr
== MIME_E_INVALID_OPTION_ID
, "ret %08x\n", hr
);
1085 PropVariantClear(&prop
);
1087 IMimeMessage_Release(msg
);
1090 static void test_BindToObject(void)
1097 hr
= MimeOleCreateMessage(NULL
, &msg
);
1098 ok(hr
== S_OK
, "ret %08x\n", hr
);
1100 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, TRUE
, &count
);
1101 ok(hr
== S_OK
, "ret %08x\n", hr
);
1102 ok(count
== 1, "got %d\n", count
);
1104 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
1105 ok(hr
== S_OK
, "ret %08x\n", hr
);
1106 IMimeBody_Release(body
);
1108 IMimeMessage_Release(msg
);
1111 static void test_BodyDeleteProp(void)
1113 static const char topic
[] = "wine topic";
1119 hr
= MimeOleCreateMessage(NULL
, &msg
);
1120 ok(hr
== S_OK
, "ret %08x\n", hr
);
1122 PropVariantInit(&prop
);
1124 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
1125 ok(hr
== S_OK
, "ret %08x\n", hr
);
1127 hr
= IMimeBody_DeleteProp(body
, "Subject");
1128 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1130 hr
= IMimeBody_DeleteProp(body
, PIDTOSTR(PID_HDR_SUBJECT
));
1131 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1134 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
1135 strcpy(prop
.pszVal
, topic
);
1136 hr
= IMimeBody_SetProp(body
, "Subject", 0, &prop
);
1137 ok(hr
== S_OK
, "ret %08x\n", hr
);
1138 PropVariantClear(&prop
);
1140 hr
= IMimeBody_DeleteProp(body
, "Subject");
1141 ok(hr
== S_OK
, "ret %08x\n", hr
);
1143 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
1144 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1147 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
1148 strcpy(prop
.pszVal
, topic
);
1149 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
1150 ok(hr
== S_OK
, "ret %08x\n", hr
);
1151 PropVariantClear(&prop
);
1153 hr
= IMimeBody_DeleteProp(body
, PIDTOSTR(PID_HDR_SUBJECT
));
1154 ok(hr
== S_OK
, "ret %08x\n", hr
);
1156 hr
= IMimeBody_GetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
1157 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1159 IMimeBody_Release(body
);
1160 IMimeMessage_Release(msg
);
1163 static void test_MimeOleGetPropertySchema(void)
1166 IMimePropertySchema
*schema
= NULL
;
1168 hr
= MimeOleGetPropertySchema(&schema
);
1169 ok(hr
== S_OK
, "ret %08x\n", hr
);
1171 IMimePropertySchema_Release(schema
);
1176 const char *content
;
1179 } mhtml_binding_test_t
;
1181 static const mhtml_binding_test_t binding_tests
[] = {
1189 "mhtml:file://%s!http://winehq.org/mhtmltest.html",
1196 static const mhtml_binding_test_t
*current_binding_test
;
1197 static IInternetProtocol
*current_binding_protocol
;
1199 static HRESULT WINAPI
BindInfo_QueryInterface(IInternetBindInfo
*iface
, REFIID riid
, void **ppv
)
1201 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetBindInfo
, riid
)) {
1207 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid
));
1208 return E_NOINTERFACE
;
1211 static ULONG WINAPI
BindInfo_AddRef(IInternetBindInfo
*iface
)
1216 static ULONG WINAPI
BindInfo_Release(IInternetBindInfo
*iface
)
1221 static HRESULT WINAPI
BindInfo_GetBindInfo(IInternetBindInfo
*iface
, DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
1223 CHECK_EXPECT(GetBindInfo
);
1225 ok(grfBINDF
!= NULL
, "grfBINDF == NULL\n");
1226 ok(pbindinfo
!= NULL
, "pbindinfo == NULL\n");
1227 ok(pbindinfo
->cbSize
== sizeof(BINDINFO
), "wrong size of pbindinfo: %d\n", pbindinfo
->cbSize
);
1229 *grfBINDF
= BINDF_ASYNCHRONOUS
| BINDF_ASYNCSTORAGE
| BINDF_PULLDATA
| BINDF_FROMURLMON
| BINDF_NEEDFILE
;
1233 static HRESULT WINAPI
BindInfo_GetBindString(IInternetBindInfo
*iface
, ULONG ulStringType
, LPOLESTR
*ppwzStr
,
1234 ULONG cEl
, ULONG
*pcElFetched
)
1236 ok(0, "unexpected call\n");
1240 static IInternetBindInfoVtbl InternetBindInfoVtbl
= {
1241 BindInfo_QueryInterface
,
1244 BindInfo_GetBindInfo
,
1245 BindInfo_GetBindString
1248 static IInternetBindInfo bind_info
= {
1249 &InternetBindInfoVtbl
1252 static HRESULT WINAPI
ServiceProvider_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
1254 ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid
));
1256 return E_NOINTERFACE
;
1259 static ULONG WINAPI
ServiceProvider_AddRef(IServiceProvider
*iface
)
1264 static ULONG WINAPI
ServiceProvider_Release(IServiceProvider
*iface
)
1269 static HRESULT WINAPI
ServiceProvider_QueryService(IServiceProvider
*iface
, REFGUID guidService
,
1270 REFIID riid
, void **ppv
)
1272 if(IsEqualGUID(&CLSID_MimeEdit
, guidService
)) {
1274 return E_NOINTERFACE
;
1277 ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService
));
1281 static const IServiceProviderVtbl ServiceProviderVtbl
= {
1282 ServiceProvider_QueryInterface
,
1283 ServiceProvider_AddRef
,
1284 ServiceProvider_Release
,
1285 ServiceProvider_QueryService
1288 static IServiceProvider service_provider
= { &ServiceProviderVtbl
};
1290 static HRESULT WINAPI
ProtocolSink_QueryInterface(IInternetProtocolSink
*iface
, REFIID riid
, void **ppv
)
1292 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetProtocolSink
, riid
)) {
1297 if(IsEqualGUID(&IID_IServiceProvider
, riid
)) {
1298 *ppv
= &service_provider
;
1303 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid
));
1304 return E_NOINTERFACE
;
1307 static ULONG WINAPI
ProtocolSink_AddRef(IInternetProtocolSink
*iface
)
1312 static ULONG WINAPI
ProtocolSink_Release(IInternetProtocolSink
*iface
)
1317 static HRESULT WINAPI
ProtocolSink_Switch(IInternetProtocolSink
*iface
, PROTOCOLDATA
*pProtocolData
)
1319 ok(0, "unexpected call\n");
1323 static HRESULT WINAPI
ProtocolSink_ReportProgress(IInternetProtocolSink
*iface
, ULONG ulStatusCode
,
1324 const WCHAR
*szStatusText
)
1326 switch(ulStatusCode
) {
1327 case BINDSTATUS_MIMETYPEAVAILABLE
:
1328 CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
1329 ok(!lstrcmpW(szStatusText
, current_binding_test
->mime
), "status text %s\n", wine_dbgstr_w(szStatusText
));
1331 case BINDSTATUS_CACHEFILENAMEAVAILABLE
:
1332 CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
1335 ok(0, "unexpected call %u %s\n", ulStatusCode
, wine_dbgstr_w(szStatusText
));
1341 static HRESULT WINAPI
ProtocolSink_ReportData(IInternetProtocolSink
*iface
, DWORD grfBSCF
, ULONG ulProgress
,
1342 ULONG ulProgressMax
)
1348 CHECK_EXPECT(ReportData
);
1350 ok(!ulProgress
, "ulProgress = %u\n", ulProgress
);
1351 ok(ulProgress
== ulProgressMax
, "ulProgress != ulProgressMax\n");
1352 ok(grfBSCF
== (BSCF_FIRSTDATANOTIFICATION
| BSCF_INTERMEDIATEDATANOTIFICATION
1353 | BSCF_LASTDATANOTIFICATION
| BSCF_DATAFULLYAVAILABLE
| BSCF_AVAILABLEDATASIZEUNKNOWN
),
1354 "grcf = %08x\n", grfBSCF
);
1356 hres
= IInternetProtocol_Read(current_binding_protocol
, buf
, sizeof(buf
), &read
);
1357 ok(hres
== S_OK
, "Read failed: %08x\n", hres
);
1359 ok(!strcmp(buf
, current_binding_test
->data
), "unexpected data: %s\n", buf
);
1361 hres
= IInternetProtocol_Read(current_binding_protocol
, buf
, sizeof(buf
), &read
);
1362 ok(hres
== S_FALSE
, "Read failed: %08x\n", hres
);
1366 static HRESULT WINAPI
ProtocolSink_ReportResult(IInternetProtocolSink
*iface
, HRESULT hrResult
, DWORD dwError
,
1369 CHECK_EXPECT(ReportResult
);
1370 ok(hrResult
== S_OK
, "hrResult = %08x\n", hrResult
);
1371 ok(!dwError
, "dwError = %u\n", dwError
);
1372 ok(!szResult
, "szResult = %s\n", wine_dbgstr_w(szResult
));
1376 static IInternetProtocolSinkVtbl InternetProtocolSinkVtbl
= {
1377 ProtocolSink_QueryInterface
,
1378 ProtocolSink_AddRef
,
1379 ProtocolSink_Release
,
1380 ProtocolSink_Switch
,
1381 ProtocolSink_ReportProgress
,
1382 ProtocolSink_ReportData
,
1383 ProtocolSink_ReportResult
1386 static IInternetProtocolSink protocol_sink
= { &InternetProtocolSinkVtbl
};
1388 static void test_mhtml_protocol_binding(const mhtml_binding_test_t
*test
)
1390 char file_name
[MAX_PATH
+32], *p
, urla
[INTERNET_MAX_URL_LENGTH
];
1391 WCHAR test_url
[INTERNET_MAX_URL_LENGTH
];
1392 IInternetProtocol
*protocol
;
1399 p
= file_name
+ GetCurrentDirectoryA(sizeof(file_name
), file_name
);
1401 strcpy(p
, "winetest.mht");
1403 file
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
1404 FILE_ATTRIBUTE_NORMAL
, NULL
);
1405 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFile failed\n");
1407 WriteFile(file
, test
->content
, strlen(test
->content
), &size
, NULL
);
1410 sprintf(urla
, test
->url
, file_name
);
1411 MultiByteToWideChar(CP_ACP
, 0, urla
, -1, test_url
, ARRAY_SIZE(test_url
));
1413 hres
= CoCreateInstance(&CLSID_IMimeHtmlProtocol
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IInternetProtocol
, (void**)&protocol
);
1414 ok(hres
== S_OK
, "Could not create protocol handler: %08x\n", hres
);
1416 hres
= IInternetProtocol_QueryInterface(protocol
, &IID_IInternetProtocolEx
, (void**)&unk
);
1417 ok(hres
== E_NOINTERFACE
, "Could get IInternetProtocolEx\n");
1419 current_binding_test
= test
;
1420 current_binding_protocol
= protocol
;
1422 SET_EXPECT(GetBindInfo
);
1423 SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
1424 SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
1425 SET_EXPECT(ReportData
);
1426 SET_EXPECT(ReportResult
);
1427 hres
= IInternetProtocol_Start(protocol
, test_url
, &protocol_sink
, &bind_info
, 0, 0);
1428 ok(hres
== S_OK
, "Start failed: %08x\n", hres
);
1429 CHECK_CALLED(GetBindInfo
);
1430 CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE
);
1431 todo_wine
CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE
);
1432 CHECK_CALLED(ReportData
);
1433 CHECK_CALLED(ReportResult
);
1435 IInternetProtocol_Release(protocol
);
1436 ret
= DeleteFileA("winetest.mht");
1437 ok(ret
, "DeleteFile failed: %u\n", GetLastError());
1440 static const struct {
1441 const WCHAR
*base_url
;
1442 const WCHAR
*relative_url
;
1443 const WCHAR
*expected_result
;
1445 } combine_tests
[] = {
1447 L
"mhtml:file:///c:/dir/test.mht", L
"http://test.org",
1448 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org"
1450 L
"mhtml:file:///c:/dir/test.mht", L
"3D\"http://test.org\"",
1451 L
"mhtml:file:///c:/dir/test.mht!x-usc:3D\"http://test.org\""
1453 L
"mhtml:file:///c:/dir/test.mht", L
"123abc",
1454 L
"mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1456 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", L
"123abc",
1457 L
"mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1459 L
"MhtMl:file:///c:/dir/test.mht!x-usc:http://test.org/dir/dir2/file.html", L
"../..",
1460 L
"mhtml:file:///c:/dir/test.mht!x-usc:../.."
1462 L
"mhtml:file:///c:/dir/test.mht!x-usc:file:///c:/dir/dir2/file.html", L
"../..",
1463 L
"mhtml:file:///c:/dir/test.mht!x-usc:../.."
1465 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", L
"",
1466 L
"mhtml:file:///c:/dir/test.mht"
1468 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", L
"mhtml:file:///d:/file.html",
1469 L
"file:///d:/file.html", TRUE
1471 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", L
"mhtml:file:///c:/dir2/test.mht!x-usc:http://test.org",
1472 L
"mhtml:file:///c:/dir2/test.mht!x-usc:http://test.org", TRUE
1474 L
"mhtml:file:///c:/dir/test.mht!http://test.org", L
"123abc",
1475 L
"mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1477 L
"mhtml:file:///c:/dir/test.mht!http://test.org", L
"",
1478 L
"mhtml:file:///c:/dir/test.mht"
1482 static void test_mhtml_protocol_info(void)
1484 WCHAR combined_url
[INTERNET_MAX_URL_LENGTH
];
1485 IInternetProtocolInfo
*protocol_info
;
1490 hres
= CoCreateInstance(&CLSID_IMimeHtmlProtocol
, NULL
, CLSCTX_INPROC_SERVER
,
1491 &IID_IInternetProtocolInfo
, (void**)&protocol_info
);
1492 ok(hres
== S_OK
, "Could not create protocol info: %08x\n", hres
);
1494 for(i
= 0; i
< ARRAY_SIZE(combine_tests
); i
++) {
1495 combined_len
= 0xdeadbeef;
1496 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, combine_tests
[i
].base_url
,
1497 combine_tests
[i
].relative_url
, ICU_BROWSER_MODE
,
1498 combined_url
, ARRAY_SIZE(combined_url
), &combined_len
, 0);
1499 todo_wine_if(combine_tests
[i
].todo
)
1500 ok(hres
== S_OK
, "[%u] CombineUrl failed: %08x\n", i
, hres
);
1501 if(SUCCEEDED(hres
)) {
1502 exlen
= lstrlenW(combine_tests
[i
].expected_result
);
1503 ok(combined_len
== exlen
, "[%u] combined len is %u, expected %u\n", i
, combined_len
, exlen
);
1504 ok(!lstrcmpW(combined_url
, combine_tests
[i
].expected_result
), "[%u] combined URL is %s, expected %s\n",
1505 i
, wine_dbgstr_w(combined_url
), wine_dbgstr_w(combine_tests
[i
].expected_result
));
1507 combined_len
= 0xdeadbeef;
1508 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, combine_tests
[i
].base_url
,
1509 combine_tests
[i
].relative_url
, ICU_BROWSER_MODE
,
1510 combined_url
, exlen
, &combined_len
, 0);
1511 ok(hres
== E_FAIL
, "[%u] CombineUrl returned: %08x\n", i
, hres
);
1512 ok(!combined_len
, "[%u] combined_len = %u\n", i
, combined_len
);
1516 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, L
"http://test.org", L
"http://test.org",
1517 ICU_BROWSER_MODE
, combined_url
, ARRAY_SIZE(combined_url
),
1519 ok(hres
== E_FAIL
, "CombineUrl failed: %08x\n", hres
);
1521 IInternetProtocolInfo_Release(protocol_info
);
1524 static HRESULT WINAPI
outer_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
1526 ok(0, "unexpected call\n");
1527 return E_NOINTERFACE
;
1530 static ULONG WINAPI
outer_AddRef(IUnknown
*iface
)
1535 static ULONG WINAPI
outer_Release(IUnknown
*iface
)
1540 static const IUnknownVtbl outer_vtbl
= {
1541 outer_QueryInterface
,
1546 static BOOL broken_mhtml_resolver
;
1548 static void test_mhtml_protocol(void)
1550 IUnknown outer
= { &outer_vtbl
};
1551 IClassFactory
*class_factory
;
1552 IUnknown
*unk
, *unk2
;
1556 /* test class factory */
1557 hres
= CoGetClassObject(&CLSID_IMimeHtmlProtocol
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IUnknown
, (void**)&unk
);
1558 ok(hres
== S_OK
, "CoGetClassObject failed: %08x\n", hres
);
1560 hres
= IUnknown_QueryInterface(unk
, &IID_IInternetProtocolInfo
, (void**)&unk2
);
1561 ok(hres
== E_NOINTERFACE
, "IInternetProtocolInfo supported\n");
1563 hres
= IUnknown_QueryInterface(unk
, &IID_IClassFactory
, (void**)&class_factory
);
1564 ok(hres
== S_OK
, "Could not get IClassFactory iface: %08x\n", hres
);
1565 IUnknown_Release(unk
);
1567 hres
= IClassFactory_CreateInstance(class_factory
, &outer
, &IID_IUnknown
, (void**)&unk
);
1568 ok(hres
== S_OK
, "CreateInstance returned: %08x\n", hres
);
1569 hres
= IUnknown_QueryInterface(unk
, &IID_IInternetProtocol
, (void**)&unk2
);
1570 ok(hres
== S_OK
, "Could not get IInternetProtocol iface: %08x\n", hres
);
1571 IUnknown_Release(unk2
);
1572 IUnknown_Release(unk
);
1574 hres
= IClassFactory_CreateInstance(class_factory
, (IUnknown
*)0xdeadbeef, &IID_IInternetProtocol
, (void**)&unk2
);
1575 ok(hres
== CLASS_E_NOAGGREGATION
, "CreateInstance returned: %08x\n", hres
);
1577 IClassFactory_Release(class_factory
);
1579 if(!broken_mhtml_resolver
)
1580 test_mhtml_protocol_info();
1582 for(i
= 0; i
< ARRAY_SIZE(binding_tests
); i
++)
1583 test_mhtml_protocol_binding(binding_tests
+ i
);
1586 static void test_MimeOleObjectFromMoniker(void)
1588 IMoniker
*mon
, *new_mon
;
1595 static const struct {
1597 const WCHAR
*mhtml_url
;
1599 {L
"file:///x:\\dir\\file.mht", L
"mhtml:file://x:\\dir\\file.mht"},
1600 {L
"file:///x:/dir/file.mht", L
"mhtml:file://x:\\dir\\file.mht"},
1601 {L
"http://www.winehq.org/index.html?query#hash", L
"mhtml:http://www.winehq.org/index.html?query#hash"},
1602 {L
"../test.mht", L
"mhtml:../test.mht"}
1605 for(i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
1606 hres
= CreateURLMoniker(NULL
, tests
[i
].url
, &mon
);
1607 ok(hres
== S_OK
, "CreateURLMoniker failed: %08x\n", hres
);
1609 hres
= CreateBindCtx(0, &bind_ctx
);
1610 ok(hres
== S_OK
, "CreateBindCtx failed: %08x\n", hres
);
1612 hres
= MimeOleObjectFromMoniker(0, mon
, bind_ctx
, &IID_IUnknown
, (void**)&unk
, &new_mon
);
1613 ok(hres
== S_OK
|| broken(!i
&& hres
== INET_E_RESOURCE_NOT_FOUND
), "MimeOleObjectFromMoniker failed: %08x\n", hres
);
1614 IBindCtx_Release(bind_ctx
);
1615 if(hres
== INET_E_RESOURCE_NOT_FOUND
) { /* winxp */
1616 win_skip("Broken MHTML behaviour found. Skipping some tests.\n");
1617 broken_mhtml_resolver
= TRUE
;
1621 hres
= IMoniker_GetDisplayName(new_mon
, NULL
, NULL
, &mhtml_url
);
1622 ok(hres
== S_OK
, "GetDisplayName failed: %08x\n", hres
);
1623 ok(!lstrcmpW(mhtml_url
, tests
[i
].mhtml_url
), "[%d] unexpected mhtml URL: %s\n", i
, wine_dbgstr_w(mhtml_url
));
1624 CoTaskMemFree(mhtml_url
);
1626 IUnknown_Release(unk
);
1627 IMoniker_Release(new_mon
);
1628 IMoniker_Release(mon
);
1634 OleInitialize(NULL
);
1635 test_CreateVirtualStream();
1636 test_CreateSecurity();
1640 test_CreateMessage();
1641 test_MessageSetProp();
1642 test_MessageGetPropInfo();
1643 test_MessageOptions();
1644 test_BindToObject();
1645 test_BodyDeleteProp();
1646 test_MimeOleGetPropertySchema();
1647 test_mhtml_message();
1648 test_MimeOleObjectFromMoniker();
1649 test_mhtml_protocol();