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
32 #include "wine/test.h"
34 #define DEFINE_EXPECT(func) \
35 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
37 #define SET_EXPECT(func) \
38 expect_ ## func = TRUE
40 #define CHECK_EXPECT(func) \
42 ok(expect_ ##func, "unexpected call " #func "\n"); \
43 expect_ ## func = FALSE; \
44 called_ ## func = TRUE; \
47 #define CHECK_EXPECT2(func) \
49 ok(expect_ ##func, "unexpected call " #func "\n"); \
50 called_ ## func = TRUE; \
53 #define CHECK_CALLED(func) \
55 ok(called_ ## func, "expected " #func "\n"); \
56 expect_ ## func = called_ ## func = FALSE; \
59 DEFINE_EXPECT(Stream_Read
);
60 DEFINE_EXPECT(Stream_Stat
);
61 DEFINE_EXPECT(Stream_Seek
);
62 DEFINE_EXPECT(Stream_Seek_END
);
63 DEFINE_EXPECT(GetBindInfo
);
64 DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
65 DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
66 DEFINE_EXPECT(ReportData
);
67 DEFINE_EXPECT(ReportResult
);
69 static const char msg1
[] =
70 "MIME-Version: 1.0\r\n"
71 "Content-Type: multipart/mixed;\r\n"
72 " boundary=\"------------1.5.0.6\";\r\n"
73 " stuff=\"du;nno\";\r\n"
74 " morestuff=\"so\\\\me\\\"thing\\\"\"\r\n"
76 "From: Huw Davies <huw@codeweavers.com>\r\n"
77 "From: Me <xxx@codeweavers.com>\r\n"
78 "To: wine-patches <wine-patches@winehq.org>\r\n"
79 "Cc: Huw Davies <huw@codeweavers.com>,\r\n"
80 " \"Fred Bloggs\" <fred@bloggs.com>\r\n"
84 "This is a multi-part message in MIME format.\r\n"
85 "--------------1.5.0.6\r\n"
86 "Content-Type: text/plain; format=fixed; charset=UTF-8\r\n"
87 "Content-Transfer-Encoding: 8bit\r\n"
90 "--------------1.5.0.6\r\n"
91 "Content-Type: text/plain; charset=\"us-ascii\"\r\n"
92 "Content-Transfer-Encoding: 7bit\r\n"
95 "--------------1.5.0.6--\r\n";
97 static const char mhtml_page1
[] =
98 "MIME-Version: 1.0\r\n"
99 "Content-Type: multipart/related; type:=\"text/html\"; boundary=\"----=_NextPart_000_00\"\r\n"
101 "------=_NextPart_000_00\r\n"
102 "Content-Type: text/html; charset=\"Windows-1252\"\r\n"
103 "Content-Transfer-Encoding: quoted-printable\r\n"
106 "------=_NextPart_000_00\r\n"
107 "Content-Type: Image/Jpeg\r\n"
108 "Content-Transfer-Encoding: base64\r\n"
109 "Content-Location: http://winehq.org/mhtmltest.html\r\n"
110 "\r\n\t\t\t\tVGVzdA==\r\n\r\n"
111 "------=_NextPart_000_00--";
113 static void test_CreateVirtualStream(void)
118 hr
= MimeOleCreateVirtualStream(&pstm
);
119 ok(hr
== S_OK
, "ret %08lx\n", hr
);
121 IStream_Release(pstm
);
124 static void test_CreateSecurity(void)
129 hr
= MimeOleCreateSecurity(&sec
);
130 ok(hr
== S_OK
, "ret %08lx\n", hr
);
132 IMimeSecurity_Release(sec
);
135 static IStream
*create_stream_from_string(const char *data
)
141 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
);
142 ok(hr
== S_OK
, "ret %08lx\n", hr
);
144 hr
= IStream_Write(stream
, data
, strlen(data
), NULL
);
145 ok(hr
== S_OK
, "Write failed: %08lx\n", hr
);
148 hr
= IStream_Seek(stream
, off
, STREAM_SEEK_SET
, NULL
);
149 ok(hr
== S_OK
, "Seek failed: %08lx\n", hr
);
154 #define test_current_encoding(a,b) _test_current_encoding(__LINE__,a,b)
155 static void _test_current_encoding(unsigned line
, IMimeBody
*mime_body
, ENCODINGTYPE encoding
)
157 ENCODINGTYPE current_encoding
;
160 hres
= IMimeBody_GetCurrentEncoding(mime_body
, ¤t_encoding
);
161 ok_(__FILE__
,line
)(hres
== S_OK
, "GetCurrentEncoding failed: %08lx\n", hres
);
162 ok_(__FILE__
,line
)(current_encoding
== encoding
, "encoding = %d, expected %d\n", current_encoding
, encoding
);
165 static void test_CreateBody(void)
169 HBODY handle
= (void *)0xdeadbeef;
173 ULONG count
, found_param
, i
;
174 MIMEPARAMINFO
*param_info
;
175 IMimeAllocator
*alloc
;
179 hr
= CoCreateInstance(&CLSID_IMimeBody
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMimeBody
, (void**)&body
);
180 ok(hr
== S_OK
, "ret %08lx\n", hr
);
182 hr
= IMimeBody_GetClassID(body
, NULL
);
183 ok(hr
== E_INVALIDARG
, "ret %08lx\n", hr
);
185 hr
= IMimeBody_GetClassID(body
, &clsid
);
186 ok(hr
== S_OK
, "ret %08lx\n", hr
);
187 ok(IsEqualGUID(&clsid
, &IID_IMimeBody
), "got %s\n", wine_dbgstr_guid(&clsid
));
189 hr
= IMimeBody_GetHandle(body
, &handle
);
190 ok(hr
== MIME_E_NO_DATA
, "ret %08lx\n", hr
);
191 ok(handle
== NULL
, "handle %p\n", handle
);
193 in
= create_stream_from_string(msg1
);
195 /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
196 hr
= IMimeBody_InitNew(body
);
197 ok(hr
== S_OK
, "ret %08lx\n", hr
);
199 test_current_encoding(body
, IET_7BIT
);
201 hr
= IMimeBody_Load(body
, in
);
202 ok(hr
== S_OK
, "ret %08lx\n", hr
);
204 IStream_Seek(in
, off
, STREAM_SEEK_CUR
, &pos
);
205 ok(pos
.LowPart
== 359, "pos %lu\n", pos
.LowPart
);
207 hr
= IMimeBody_IsContentType(body
, "multipart", "mixed");
208 ok(hr
== S_OK
, "ret %08lx\n", hr
);
209 hr
= IMimeBody_IsContentType(body
, "text", "plain");
210 ok(hr
== S_FALSE
, "ret %08lx\n", hr
);
211 hr
= IMimeBody_IsContentType(body
, NULL
, "mixed");
212 ok(hr
== S_OK
, "ret %08lx\n", hr
);
213 hr
= IMimeBody_IsType(body
, IBT_EMPTY
);
214 ok(hr
== S_OK
, "got %08lx\n", hr
);
216 hr
= IMimeBody_SetData(body
, IET_8BIT
, "text", "plain", &IID_IStream
, in
);
217 ok(hr
== S_OK
, "ret %08lx\n", hr
);
218 hr
= IMimeBody_IsContentType(body
, "text", "plain");
220 ok(hr
== S_OK
, "ret %08lx\n", hr
);
221 test_current_encoding(body
, IET_8BIT
);
223 memset(&offsets
, 0xcc, sizeof(offsets
));
224 hr
= IMimeBody_GetOffsets(body
, &offsets
);
225 ok(hr
== MIME_E_NO_DATA
, "ret %08lx\n", hr
);
226 ok(offsets
.cbBoundaryStart
== 0, "got %ld\n", offsets
.cbBoundaryStart
);
227 ok(offsets
.cbHeaderStart
== 0, "got %ld\n", offsets
.cbHeaderStart
);
228 ok(offsets
.cbBodyStart
== 0, "got %ld\n", offsets
.cbBodyStart
);
229 ok(offsets
.cbBodyEnd
== 0, "got %ld\n", offsets
.cbBodyEnd
);
231 hr
= IMimeBody_IsType(body
, IBT_EMPTY
);
232 ok(hr
== S_FALSE
, "got %08lx\n", hr
);
234 hr
= MimeOleGetAllocator(&alloc
);
235 ok(hr
== S_OK
, "ret %08lx\n", hr
);
237 hr
= IMimeBody_GetParameters(body
, "nothere", &count
, ¶m_info
);
238 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
239 ok(count
== 0, "got %ld\n", count
);
240 ok(!param_info
, "got %p\n", param_info
);
242 hr
= IMimeBody_GetParameters(body
, "bar", &count
, ¶m_info
);
243 ok(hr
== S_OK
, "ret %08lx\n", hr
);
244 ok(count
== 0, "got %ld\n", count
);
245 ok(!param_info
, "got %p\n", param_info
);
247 hr
= IMimeBody_GetParameters(body
, "Content-Type", &count
, ¶m_info
);
248 ok(hr
== S_OK
, "ret %08lx\n", hr
);
249 todo_wine
/* native adds a charset parameter */
250 ok(count
== 4, "got %ld\n", count
);
251 ok(param_info
!= NULL
, "got %p\n", param_info
);
254 for(i
= 0; i
< count
; i
++)
256 if(!strcmp(param_info
[i
].pszName
, "morestuff"))
259 ok(!strcmp(param_info
[i
].pszData
, "so\\me\"thing\""),
260 "got %s\n", param_info
[i
].pszData
);
262 else if(!strcmp(param_info
[i
].pszName
, "stuff"))
265 ok(!strcmp(param_info
[i
].pszData
, "du;nno"),
266 "got %s\n", param_info
[i
].pszData
);
269 ok(found_param
== 2, "matched %ld params\n", found_param
);
271 hr
= IMimeAllocator_FreeParamInfoArray(alloc
, count
, param_info
, TRUE
);
272 ok(hr
== S_OK
, "ret %08lx\n", hr
);
273 IMimeAllocator_Release(alloc
);
276 IMimeBody_Release(body
);
280 IStream IStream_iface
;
285 static inline TestStream
*impl_from_IStream(IStream
*iface
)
287 return CONTAINING_RECORD(iface
, TestStream
, IStream_iface
);
290 static HRESULT WINAPI
Stream_QueryInterface(IStream
*iface
, REFIID riid
, void **ppv
)
292 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_ISequentialStream
, riid
) || IsEqualGUID(&IID_IStream
, riid
)) {
297 ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid
));
299 return E_NOINTERFACE
;
302 static ULONG WINAPI
Stream_AddRef(IStream
*iface
)
304 TestStream
*This
= impl_from_IStream(iface
);
305 return InterlockedIncrement(&This
->ref
);
308 static ULONG WINAPI
Stream_Release(IStream
*iface
)
310 TestStream
*This
= impl_from_IStream(iface
);
311 ULONG ref
= InterlockedDecrement(&This
->ref
);
314 HeapFree(GetProcessHeap(), 0, This
);
319 static HRESULT WINAPI
Stream_Read(IStream
*iface
, void *pv
, ULONG cb
, ULONG
*pcbRead
)
321 TestStream
*This
= impl_from_IStream(iface
);
325 CHECK_EXPECT(Stream_Read
);
327 for(i
= 0; i
< cb
; i
++)
328 output
[i
] = '0' + This
->pos
++;
333 static HRESULT WINAPI
Stream_Write(IStream
*iface
, const void *pv
, ULONG cb
, ULONG
*pcbWritten
)
335 ok(0, "unexpected call\n");
339 static DWORD expect_seek_pos
;
341 static HRESULT WINAPI
Stream_Seek(IStream
*iface
, LARGE_INTEGER dlibMove
, DWORD dwOrigin
,
342 ULARGE_INTEGER
*plibNewPosition
)
344 TestStream
*This
= impl_from_IStream(iface
);
346 if(dwOrigin
== STREAM_SEEK_END
) {
347 CHECK_EXPECT(Stream_Seek_END
);
348 ok(dlibMove
.QuadPart
== expect_seek_pos
, "unexpected seek pos %lu\n", dlibMove
.LowPart
);
350 plibNewPosition
->QuadPart
= 10;
354 CHECK_EXPECT(Stream_Seek
);
356 ok(dlibMove
.QuadPart
== expect_seek_pos
, "unexpected seek pos %lu\n", dlibMove
.LowPart
);
357 ok(dwOrigin
== STREAM_SEEK_SET
, "dwOrigin = %ld\n", dwOrigin
);
358 This
->pos
= dlibMove
.QuadPart
;
360 plibNewPosition
->QuadPart
= This
->pos
;
364 static HRESULT WINAPI
Stream_SetSize(IStream
*iface
, ULARGE_INTEGER libNewSize
)
366 ok(0, "unexpected call\n");
370 static HRESULT WINAPI
Stream_CopyTo(IStream
*iface
, IStream
*pstm
, ULARGE_INTEGER cb
,
371 ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
373 ok(0, "unexpected call\n");
377 static HRESULT WINAPI
Stream_Commit(IStream
*iface
, DWORD grfCommitFlags
)
379 ok(0, "unexpected call\n");
383 static HRESULT WINAPI
Stream_Revert(IStream
*iface
)
385 ok(0, "unexpected call\n");
389 static HRESULT WINAPI
Stream_LockRegion(IStream
*iface
, ULARGE_INTEGER libOffset
,
390 ULARGE_INTEGER cb
, DWORD dwLockType
)
392 ok(0, "unexpected call\n");
396 static HRESULT WINAPI
Stream_UnlockRegion(IStream
*iface
,
397 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
399 ok(0, "unexpected call\n");
403 static HRESULT WINAPI
Stream_Stat(IStream
*iface
, STATSTG
*pstatstg
, DWORD dwStatFlag
)
405 CHECK_EXPECT(Stream_Stat
);
406 ok(dwStatFlag
== STATFLAG_NONAME
, "dwStatFlag = %lx\n", dwStatFlag
);
410 static HRESULT WINAPI
Stream_Clone(IStream
*iface
, IStream
**ppstm
)
412 ok(0, "unexpected call\n");
416 static const IStreamVtbl StreamVtbl
= {
417 Stream_QueryInterface
,
433 static IStream
*create_test_stream(void)
436 stream
= HeapAlloc(GetProcessHeap(), 0, sizeof(*stream
));
437 stream
->IStream_iface
.lpVtbl
= &StreamVtbl
;
440 return &stream
->IStream_iface
;
443 #define test_stream_read(a,b,c,d) _test_stream_read(__LINE__,a,b,c,d)
444 static void _test_stream_read(unsigned line
, IStream
*stream
, HRESULT exhres
, const char *exdata
, unsigned read_size
)
446 ULONG read
= 0xdeadbeed, exread
= strlen(exdata
);
451 read_size
= sizeof(buf
)-1;
453 hres
= IStream_Read(stream
, buf
, read_size
, &read
);
454 ok_(__FILE__
,line
)(hres
== exhres
, "Read returned %08lx, expected %08lx\n", hres
, exhres
);
455 ok_(__FILE__
,line
)(read
== exread
, "unexpected read size %lu, expected %lu\n", read
, exread
);
457 ok_(__FILE__
,line
)(read
== exread
&& !memcmp(buf
, exdata
, read
), "unexpected data %s\n", buf
);
460 static void test_SetData(void)
462 IStream
*stream
, *stream2
, *test_stream
;
466 hr
= CoCreateInstance(&CLSID_IMimeBody
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMimeBody
, (void**)&body
);
467 ok(hr
== S_OK
, "ret %08lx\n", hr
);
469 /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
470 hr
= IMimeBody_InitNew(body
);
471 ok(hr
== S_OK
, "ret %08lx\n", hr
);
473 stream
= create_stream_from_string(msg1
);
474 hr
= IMimeBody_Load(body
, stream
);
475 ok(hr
== S_OK
, "ret %08lx\n", hr
);
476 IStream_Release(stream
);
478 test_stream
= create_test_stream();
479 hr
= IMimeBody_SetData(body
, IET_BINARY
, "text", "plain", &IID_IStream
, test_stream
);
481 ok(hr
== S_OK
, "ret %08lx\n", hr
);
482 hr
= IMimeBody_IsContentType(body
, "text", "plain");
484 ok(hr
== S_OK
, "ret %08lx\n", hr
);
486 test_current_encoding(body
, IET_BINARY
);
488 SET_EXPECT(Stream_Stat
);
489 SET_EXPECT(Stream_Seek_END
);
490 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
491 CHECK_CALLED(Stream_Stat
);
492 CHECK_CALLED(Stream_Seek_END
);
493 ok(hr
== S_OK
, "GetData failed %08lx\n", hr
);
494 ok(stream
!= test_stream
, "unexpected stream\n");
496 SET_EXPECT(Stream_Seek
);
497 SET_EXPECT(Stream_Read
);
498 test_stream_read(stream
, S_OK
, "012", 3);
499 CHECK_CALLED(Stream_Seek
);
500 CHECK_CALLED(Stream_Read
);
502 SET_EXPECT(Stream_Stat
);
503 SET_EXPECT(Stream_Seek_END
);
504 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream2
);
505 CHECK_CALLED(Stream_Stat
);
506 CHECK_CALLED(Stream_Seek_END
);
507 ok(hr
== S_OK
, "GetData failed %08lx\n", hr
);
508 ok(stream2
!= stream
, "unexpected stream\n");
510 SET_EXPECT(Stream_Seek
);
511 SET_EXPECT(Stream_Read
);
512 test_stream_read(stream2
, S_OK
, "01", 2);
513 CHECK_CALLED(Stream_Seek
);
514 CHECK_CALLED(Stream_Read
);
517 SET_EXPECT(Stream_Seek
);
518 SET_EXPECT(Stream_Read
);
519 test_stream_read(stream
, S_OK
, "345", 3);
520 CHECK_CALLED(Stream_Seek
);
521 CHECK_CALLED(Stream_Read
);
523 IStream_Release(stream
);
524 IStream_Release(stream2
);
525 IStream_Release(test_stream
);
527 stream
= create_stream_from_string(" \t\r\n|}~YWJj ZGV|}~mZw== \t"); /* "abcdefg" in base64 obscured by invalid chars */
528 hr
= IMimeBody_SetData(body
, IET_BASE64
, "text", "plain", &IID_IStream
, stream
);
529 IStream_Release(stream
);
530 ok(hr
== S_OK
, "SetData failed: %08lx\n", hr
);
532 test_current_encoding(body
, IET_BASE64
);
534 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
535 ok(hr
== S_OK
, "GetData failed %08lx\n", hr
);
537 test_stream_read(stream
, S_OK
, "abc", 3);
538 test_stream_read(stream
, S_OK
, "defg", -1);
540 IStream_Release(stream
);
542 hr
= IMimeBody_GetData(body
, IET_BASE64
, &stream
);
543 ok(hr
== S_OK
, "GetData failed %08lx\n", hr
);
545 test_stream_read(stream
, S_OK
, " \t\r", 3);
546 IStream_Release(stream
);
548 stream
= create_stream_from_string(" =3d=3D\"one\" \t=\r\ntw= o=\nx3\n=34\r\n5");
549 hr
= IMimeBody_SetData(body
, IET_QP
, "text", "plain", &IID_IStream
, stream
);
550 IStream_Release(stream
);
551 ok(hr
== S_OK
, "SetData failed: %08lx\n", hr
);
553 test_current_encoding(body
, IET_QP
);
555 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
556 ok(hr
== S_OK
, "GetData failed %08lx\n", hr
);
558 test_stream_read(stream
, S_OK
, " ==\"one\" \ttw=o=3\n4\r\n5", -1);
560 IStream_Release(stream
);
562 IMimeBody_Release(body
);
565 static void test_Allocator(void)
568 IMimeAllocator
*alloc
;
570 hr
= MimeOleGetAllocator(&alloc
);
571 ok(hr
== S_OK
, "ret %08lx\n", hr
);
572 IMimeAllocator_Release(alloc
);
575 static void test_CreateMessage(void)
585 FINDBODY find_struct
;
589 char text
[] = "text";
592 static const char att_pritype
[] = "att:pri-content-type";
594 hr
= MimeOleCreateMessage(NULL
, &msg
);
595 ok(hr
== S_OK
, "ret %08lx\n", hr
);
597 stream
= create_stream_from_string(msg1
);
599 hr
= IMimeMessage_Load(msg
, stream
);
600 ok(hr
== S_OK
, "ret %08lx\n", hr
);
602 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, TRUE
, &count
);
603 ok(hr
== S_OK
, "ret %08lx\n", hr
);
604 ok(count
== 3, "got %ld\n", count
);
606 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, FALSE
, &count
);
607 ok(hr
== S_OK
, "ret %08lx\n", hr
);
608 ok(count
== 3, "got %ld\n", count
);
610 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
611 ok(hr
== S_OK
, "ret %08lx\n", hr
);
612 hr
= IMimeBody_GetOffsets(body
, &offsets
);
613 ok(hr
== S_OK
, "ret %08lx\n", hr
);
614 ok(offsets
.cbBoundaryStart
== 0, "got %ld\n", offsets
.cbBoundaryStart
);
615 ok(offsets
.cbHeaderStart
== 0, "got %ld\n", offsets
.cbHeaderStart
);
616 ok(offsets
.cbBodyStart
== 359, "got %ld\n", offsets
.cbBodyStart
);
617 ok(offsets
.cbBodyEnd
== 666, "got %ld\n", offsets
.cbBodyEnd
);
618 IMimeBody_Release(body
);
620 hr
= IMimeMessage_GetBody(msg
, IBL_ROOT
, NULL
, &hbody
);
621 ok(hr
== S_OK
, "ret %08lx\n", hr
);
623 hr
= IMimeBody_GetHandle(body
, NULL
);
624 ok(hr
== E_INVALIDARG
, "ret %08lx\n", hr
);
626 hr
= IMimeBody_GetHandle(body
, &handle
);
627 ok(hr
== S_OK
, "ret %08lx\n", hr
);
628 ok(handle
!= NULL
, "handle %p\n", handle
);
630 hr
= IMimeMessage_GetBody(msg
, IBL_PARENT
, hbody
, NULL
);
631 ok(hr
== E_INVALIDARG
, "ret %08lx\n", hr
);
633 hbody2
= (HBODY
)0xdeadbeef;
634 hr
= IMimeMessage_GetBody(msg
, IBL_PARENT
, hbody
, &hbody2
);
635 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
636 ok(hbody2
== NULL
, "hbody2 %p\n", hbody2
);
638 PropVariantInit(&prop
);
639 hr
= IMimeMessage_GetBodyProp(msg
, hbody
, att_pritype
, 0, &prop
);
640 ok(hr
== S_OK
, "ret %08lx\n", hr
);
641 ok(prop
.vt
== VT_LPSTR
, "vt %08x\n", prop
.vt
);
642 ok(!strcasecmp(prop
.pszVal
, "multipart"), "got %s\n", prop
.pszVal
);
643 PropVariantClear(&prop
);
645 hr
= IMimeMessage_GetBody(msg
, IBL_FIRST
, hbody
, &hbody
);
646 ok(hr
== S_OK
, "ret %08lx\n", hr
);
647 hr
= IMimeMessage_BindToObject(msg
, hbody
, &IID_IMimeBody
, (void**)&body
);
648 ok(hr
== S_OK
, "ret %08lx\n", hr
);
650 hr
= IMimeBody_GetHandle(body
, &handle
);
651 ok(hr
== S_OK
, "ret %08lx\n", hr
);
652 ok(handle
== hbody
, "handle %p\n", handle
);
654 hr
= IMimeBody_GetOffsets(body
, &offsets
);
655 ok(hr
== S_OK
, "ret %08lx\n", hr
);
656 ok(offsets
.cbBoundaryStart
== 405, "got %ld\n", offsets
.cbBoundaryStart
);
657 ok(offsets
.cbHeaderStart
== 428, "got %ld\n", offsets
.cbHeaderStart
);
658 ok(offsets
.cbBodyStart
== 518, "got %ld\n", offsets
.cbBodyStart
);
659 ok(offsets
.cbBodyEnd
== 523, "got %ld\n", offsets
.cbBodyEnd
);
661 hr
= IMimeBody_GetCharset(body
, &hcs
);
662 ok(hr
== S_OK
, "ret %08lx\n", hr
);
665 ok(hcs
!= NULL
, "Expected non-NULL charset\n");
668 IMimeBody_Release(body
);
670 hr
= IMimeMessage_GetBody(msg
, IBL_NEXT
, hbody
, &hbody
);
671 ok(hr
== S_OK
, "ret %08lx\n", hr
);
672 hr
= IMimeMessage_BindToObject(msg
, hbody
, &IID_IMimeBody
, (void**)&body
);
673 ok(hr
== S_OK
, "ret %08lx\n", hr
);
675 hr
= IMimeBody_GetHandle(body
, &handle
);
676 ok(hr
== S_OK
, "ret %08lx\n", hr
);
677 ok(handle
== hbody
, "handle %p\n", handle
);
679 hr
= IMimeBody_GetOffsets(body
, &offsets
);
680 ok(hr
== S_OK
, "ret %08lx\n", hr
);
681 ok(offsets
.cbBoundaryStart
== 525, "got %ld\n", offsets
.cbBoundaryStart
);
682 ok(offsets
.cbHeaderStart
== 548, "got %ld\n", offsets
.cbHeaderStart
);
683 ok(offsets
.cbBodyStart
== 629, "got %ld\n", offsets
.cbBodyStart
);
684 ok(offsets
.cbBodyEnd
== 639, "got %ld\n", offsets
.cbBodyEnd
);
685 IMimeBody_Release(body
);
687 find_struct
.pszPriType
= text
;
688 find_struct
.pszSubType
= NULL
;
690 hr
= IMimeMessage_FindFirst(msg
, &find_struct
, &hbody
);
691 ok(hr
== S_OK
, "ret %08lx\n", hr
);
693 hr
= IMimeMessage_FindNext(msg
, &find_struct
, &hbody
);
694 ok(hr
== S_OK
, "ret %08lx\n", hr
);
696 hr
= IMimeMessage_FindNext(msg
, &find_struct
, &hbody
);
697 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
699 hr
= IMimeMessage_GetAttachments(msg
, &count
, &body_list
);
700 ok(hr
== S_OK
, "ret %08lx\n", hr
);
701 ok(count
== 2, "got %ld\n", count
);
704 IMimeBody
*attachment
;
707 PropVariantInit(&prop
);
709 hr
= IMimeMessage_BindToObject(msg
, body_list
[0], &IID_IMimeBody
, (void**)&attachment
);
710 ok(hr
== S_OK
, "ret %08lx\n", hr
);
712 hr
= IMimeBody_IsContentType(attachment
, "multipart", NULL
);
713 ok(hr
== S_FALSE
, "ret %08lx\n", hr
);
715 test_current_encoding(attachment
, IET_8BIT
);
718 hr
= IMimeBody_GetProp(attachment
, "Content-Transfer-Encoding", 0, &prop
);
719 ok(hr
== S_OK
, "ret %08lx\n", hr
);
721 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
722 ok(!strcmp(prop
.pszVal
, "8bit"), "got %s\n", prop
.pszVal
);
723 PropVariantClear(&prop
);
725 hr
= IMimeBody_IsType(attachment
, IBT_ATTACHMENT
);
726 todo_wine
ok(hr
== S_FALSE
, "ret %08lx\n", hr
);
728 IMimeBody_Release(attachment
);
730 hr
= IMimeMessage_BindToObject(msg
, body_list
[1], &IID_IMimeBody
, (void**)&attachment
);
731 ok(hr
== S_OK
, "ret %08lx\n", hr
);
733 hr
= IMimeBody_IsContentType(attachment
, "multipart", NULL
);
734 ok(hr
== S_FALSE
, "ret %08lx\n", hr
);
736 test_current_encoding(attachment
, IET_7BIT
);
739 hr
= IMimeBody_GetProp(attachment
, "Content-Transfer-Encoding", 0, &prop
);
740 ok(hr
== S_OK
, "ret %08lx\n", hr
);
741 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
742 ok(!strcmp(prop
.pszVal
, "7bit"), "got %s\n", prop
.pszVal
);
743 PropVariantClear(&prop
);
745 hr
= IMimeBody_IsType(attachment
, IBT_ATTACHMENT
);
746 ok(hr
== S_OK
, "ret %08lx\n", hr
);
748 IMimeBody_Release(attachment
);
750 CoTaskMemFree(body_list
);
752 hr
= IMimeBody_GetCharset(body
, &hcs
);
753 ok(hr
== S_OK
, "ret %08lx\n", hr
);
756 ok(hcs
!= NULL
, "Expected non-NULL charset\n");
759 IMimeMessage_Release(msg
);
761 ref
= IStream_AddRef(stream
);
763 broken(ref
== 1), /* win95 */
765 IStream_Release(stream
);
767 IStream_Release(stream
);
770 static void test_mhtml_message(void)
772 IMimeMessage
*mime_message
;
773 IMimeBody
*mime_body
;
779 hres
= MimeOleCreateMessage(NULL
, &mime_message
);
780 ok(hres
== S_OK
, "MimeOleCreateMessage failed: %08lx\n", hres
);
782 stream
= create_stream_from_string(mhtml_page1
);
783 hres
= IMimeMessage_Load(mime_message
, stream
);
784 IStream_Release(stream
);
785 ok(hres
== S_OK
, "Load failed: %08lx\n", hres
);
787 hres
= IMimeMessage_CountBodies(mime_message
, HBODY_ROOT
, TRUE
, &count
);
788 ok(hres
== S_OK
, "CountBodies failed: %08lx\n", hres
);
789 ok(count
== 3, "got %ld\n", count
);
791 hres
= IMimeMessage_GetAttachments(mime_message
, &count
, &body_list
);
792 ok(hres
== S_OK
, "GetAttachments failed: %08lx\n", hres
);
793 ok(count
== 2, "count = %lu\n", count
);
795 hres
= IMimeMessage_BindToObject(mime_message
, body_list
[0], &IID_IMimeBody
, (void**)&mime_body
);
796 ok(hres
== S_OK
, "BindToObject failed: %08lx\n", hres
);
798 hres
= IMimeBody_GetData(mime_body
, IET_BINARY
, &stream
);
799 ok(hres
== S_OK
, "GetData failed: %08lx\n", hres
);
800 test_stream_read(stream
, S_OK
, "<HTML></HTML>", -1);
801 IStream_Release(stream
);
803 test_current_encoding(mime_body
, IET_QP
);
805 IMimeBody_Release(mime_body
);
807 hres
= IMimeMessage_BindToObject(mime_message
, body_list
[1], &IID_IMimeBody
, (void**)&mime_body
);
808 ok(hres
== S_OK
, "BindToObject failed: %08lx\n", hres
);
810 test_current_encoding(mime_body
, IET_BASE64
);
812 hres
= IMimeBody_GetData(mime_body
, IET_BINARY
, &stream
);
813 ok(hres
== S_OK
, "GetData failed: %08lx\n", hres
);
814 test_stream_read(stream
, S_OK
, "Test", -1);
815 IStream_Release(stream
);
817 IMimeBody_Release(mime_body
);
819 CoTaskMemFree(body_list
);
821 IMimeMessage_Release(mime_message
);
824 static void test_MessageSetProp(void)
826 static const char topic
[] = "wine topic";
832 hr
= MimeOleCreateMessage(NULL
, &msg
);
833 ok(hr
== S_OK
, "ret %08lx\n", hr
);
835 PropVariantInit(&prop
);
837 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
838 ok(hr
== S_OK
, "ret %08lx\n", hr
);
840 hr
= IMimeBody_SetProp(body
, NULL
, 0, &prop
);
841 ok(hr
== E_INVALIDARG
, "ret %08lx\n", hr
);
843 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, NULL
);
844 ok(hr
== E_INVALIDARG
, "ret %08lx\n", hr
);
847 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
848 strcpy(prop
.pszVal
, topic
);
849 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, &prop
);
850 ok(hr
== S_OK
, "ret %08lx\n", hr
);
851 PropVariantClear(&prop
);
853 hr
= IMimeBody_GetProp(body
, NULL
, 0, &prop
);
854 ok(hr
== E_INVALIDARG
, "ret %08lx\n", hr
);
856 hr
= IMimeBody_GetProp(body
, "Thread-Topic", 0, NULL
);
857 ok(hr
== E_INVALIDARG
, "ret %08lx\n", hr
);
859 hr
= IMimeBody_GetProp(body
, "Wine-Topic", 0, &prop
);
860 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
863 hr
= IMimeBody_GetProp(body
, "Thread-Topic", 0, &prop
);
864 ok(hr
== S_OK
, "ret %08lx\n", hr
);
867 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
868 ok(!strcmp(prop
.pszVal
, topic
), "got %s\n", prop
.pszVal
);
869 PropVariantClear(&prop
);
873 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
874 strcpy(prop
.pszVal
, topic
);
875 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
876 ok(hr
== S_OK
, "ret %08lx\n", hr
);
877 PropVariantClear(&prop
);
880 hr
= IMimeBody_GetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
881 ok(hr
== S_OK
, "ret %08lx\n", hr
);
884 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
885 ok(!strcmp(prop
.pszVal
, topic
), "got %s\n", prop
.pszVal
);
886 PropVariantClear(&prop
);
889 /* Using the name or PID returns the same result. */
891 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
892 ok(hr
== S_OK
, "ret %08lx\n", hr
);
895 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
896 ok(!strcmp(prop
.pszVal
, topic
), "got %s\n", prop
.pszVal
);
897 PropVariantClear(&prop
);
901 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
902 ok(hr
== S_OK
, "ret %08lx\n", hr
);
905 ok(prop
.vt
== VT_LPWSTR
, "type %d\n", prop
.vt
);
906 ok(!lstrcmpW(prop
.pwszVal
, L
"wine topic"), "got %s\n", wine_dbgstr_w(prop
.pwszVal
));
907 PropVariantClear(&prop
);
911 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
912 strcpy(prop
.pszVal
, topic
);
913 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_TO
), 0, &prop
);
914 ok(hr
== S_OK
, "ret %08lx\n", hr
);
915 PropVariantClear(&prop
);
917 /* Out of Range PID */
919 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
920 strcpy(prop
.pszVal
, topic
);
921 hr
= IMimeBody_SetProp(body
, PIDTOSTR(124), 0, &prop
);
922 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
923 PropVariantClear(&prop
);
925 IMimeBody_Release(body
);
926 IMimeMessage_Release(msg
);
929 static void test_MessageGetPropInfo(void)
931 static const char topic
[] = "wine topic";
932 static const char subject
[] = "wine testing";
939 hr
= MimeOleCreateMessage(NULL
, &msg
);
940 ok(hr
== S_OK
, "ret %08lx\n", hr
);
942 PropVariantInit(&prop
);
944 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
945 ok(hr
== S_OK
, "ret %08lx\n", hr
);
948 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
949 strcpy(prop
.pszVal
, topic
);
950 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, &prop
);
951 ok(hr
== S_OK
, "ret %08lx\n", hr
);
952 PropVariantClear(&prop
);
955 prop
.pszVal
= CoTaskMemAlloc(strlen(subject
)+1);
956 strcpy(prop
.pszVal
, subject
);
957 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
958 ok(hr
== S_OK
, "ret %08lx\n", hr
);
959 PropVariantClear(&prop
);
961 memset(&info
, 0, sizeof(info
));
962 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
963 hr
= IMimeBody_GetPropInfo(body
, NULL
, &info
);
964 ok(hr
== E_INVALIDARG
, "ret %08lx\n", hr
);
966 memset(&info
, 0, sizeof(info
));
967 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
968 hr
= IMimeBody_GetPropInfo(body
, "Subject", NULL
);
969 ok(hr
== E_INVALIDARG
, "ret %08lx\n", hr
);
971 memset(&info
, 0xfe, sizeof(info
));
972 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
973 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
974 ok(hr
== S_OK
, "ret %08lx\n", hr
);
977 ok(info
.dwMask
& (PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
), "Invalid mask 0x%08lx\n", info
.dwFlags
);
978 todo_wine
ok(info
.dwFlags
& 0x10000000, "Invalid flags 0x%08lx\n", info
.dwFlags
);
979 ok(info
.ietEncoding
== 0, "Invalid encoding %d\n", info
.ietEncoding
);
980 ok(info
.dwPropId
== PID_HDR_SUBJECT
, "Invalid propid %ld\n", info
.dwPropId
);
981 ok(info
.cValues
== 0xfefefefe, "Invalid cValues %ld\n", info
.cValues
);
984 memset(&info
, 0xfe, sizeof(info
));
986 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
987 ok(hr
== S_OK
, "ret %08lx\n", hr
);
990 ok(info
.dwMask
== 0, "Invalid mask 0x%08lx\n", info
.dwFlags
);
991 ok(info
.dwFlags
== 0xfefefefe, "Invalid flags 0x%08lx\n", info
.dwFlags
);
992 ok(info
.ietEncoding
== -16843010, "Invalid encoding %d\n", info
.ietEncoding
);
993 ok(info
.dwPropId
== -16843010, "Invalid propid %ld\n", info
.dwPropId
);
996 memset(&info
, 0xfe, sizeof(info
));
998 info
.dwPropId
= 1024;
999 info
.ietEncoding
= 99;
1000 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
1001 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1004 ok(info
.dwMask
== 0, "Invalid mask 0x%08lx\n", info
.dwFlags
);
1005 ok(info
.dwFlags
== 0xfefefefe, "Invalid flags 0x%08lx\n", info
.dwFlags
);
1006 ok(info
.ietEncoding
== 99, "Invalid encoding %d\n", info
.ietEncoding
);
1007 ok(info
.dwPropId
== 1024, "Invalid propid %ld\n", info
.dwPropId
);
1010 memset(&info
, 0, sizeof(info
));
1011 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
1012 hr
= IMimeBody_GetPropInfo(body
, "Invalid Property", &info
);
1013 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
1015 IMimeBody_Release(body
);
1016 IMimeMessage_Release(msg
);
1019 static void test_MessageOptions(void)
1021 static const char string
[] = "XXXXX";
1022 static const char zero
[] = "0";
1027 hr
= MimeOleCreateMessage(NULL
, &msg
);
1028 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1030 PropVariantInit(&prop
);
1033 prop
.boolVal
= TRUE
;
1034 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1035 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1036 PropVariantClear(&prop
);
1038 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1039 todo_wine
ok(hr
== S_OK
, "ret %08lx\n", hr
);
1040 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1041 todo_wine
ok(prop
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.boolVal
);
1042 PropVariantClear(&prop
);
1045 prop
.pszVal
= CoTaskMemAlloc(strlen(string
)+1);
1046 strcpy(prop
.pszVal
, string
);
1047 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1048 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1049 PropVariantClear(&prop
);
1051 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1052 todo_wine
ok(hr
== S_OK
, "ret %08lx\n", hr
);
1053 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1054 todo_wine
ok(prop
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.boolVal
);
1055 PropVariantClear(&prop
);
1057 /* Invalid property type doesn't change the value */
1059 prop
.pszVal
= CoTaskMemAlloc(strlen(zero
)+1);
1060 strcpy(prop
.pszVal
, zero
);
1061 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1062 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1063 PropVariantClear(&prop
);
1065 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1066 todo_wine
ok(hr
== S_OK
, "ret %08lx\n", hr
);
1067 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1068 todo_wine
ok(prop
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.boolVal
);
1069 PropVariantClear(&prop
);
1073 prop
.boolVal
= TRUE
;
1074 hr
= IMimeMessage_SetOption(msg
, 0xff00000a, &prop
);
1075 ok(hr
== MIME_E_INVALID_OPTION_ID
, "ret %08lx\n", hr
);
1076 PropVariantClear(&prop
);
1078 /* Out of range before type. */
1081 hr
= IMimeMessage_SetOption(msg
, 0xff00000a, &prop
);
1082 ok(hr
== MIME_E_INVALID_OPTION_ID
, "ret %08lx\n", hr
);
1083 PropVariantClear(&prop
);
1085 IMimeMessage_Release(msg
);
1088 static void test_BindToObject(void)
1095 hr
= MimeOleCreateMessage(NULL
, &msg
);
1096 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1098 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, TRUE
, &count
);
1099 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1100 ok(count
== 1, "got %ld\n", count
);
1102 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
1103 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1104 IMimeBody_Release(body
);
1106 IMimeMessage_Release(msg
);
1109 static void test_BodyDeleteProp(void)
1111 static const char topic
[] = "wine topic";
1117 hr
= MimeOleCreateMessage(NULL
, &msg
);
1118 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1120 PropVariantInit(&prop
);
1122 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
1123 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1125 hr
= IMimeBody_DeleteProp(body
, "Subject");
1126 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
1128 hr
= IMimeBody_DeleteProp(body
, PIDTOSTR(PID_HDR_SUBJECT
));
1129 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
1132 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
1133 strcpy(prop
.pszVal
, topic
);
1134 hr
= IMimeBody_SetProp(body
, "Subject", 0, &prop
);
1135 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1136 PropVariantClear(&prop
);
1138 hr
= IMimeBody_DeleteProp(body
, "Subject");
1139 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1141 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
1142 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
1145 prop
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
1146 strcpy(prop
.pszVal
, topic
);
1147 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
1148 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1149 PropVariantClear(&prop
);
1151 hr
= IMimeBody_DeleteProp(body
, PIDTOSTR(PID_HDR_SUBJECT
));
1152 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1154 hr
= IMimeBody_GetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
1155 ok(hr
== MIME_E_NOT_FOUND
, "ret %08lx\n", hr
);
1157 IMimeBody_Release(body
);
1158 IMimeMessage_Release(msg
);
1161 static void test_MimeOleGetPropertySchema(void)
1164 IMimePropertySchema
*schema
= NULL
;
1166 hr
= MimeOleGetPropertySchema(&schema
);
1167 ok(hr
== S_OK
, "ret %08lx\n", hr
);
1169 IMimePropertySchema_Release(schema
);
1174 const char *content
;
1177 } mhtml_binding_test_t
;
1179 static const mhtml_binding_test_t binding_tests
[] = {
1187 "mhtml:file://%s!http://winehq.org/mhtmltest.html",
1194 static const mhtml_binding_test_t
*current_binding_test
;
1195 static IInternetProtocol
*current_binding_protocol
;
1197 static HRESULT WINAPI
BindInfo_QueryInterface(IInternetBindInfo
*iface
, REFIID riid
, void **ppv
)
1199 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetBindInfo
, riid
)) {
1205 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid
));
1206 return E_NOINTERFACE
;
1209 static ULONG WINAPI
BindInfo_AddRef(IInternetBindInfo
*iface
)
1214 static ULONG WINAPI
BindInfo_Release(IInternetBindInfo
*iface
)
1219 static HRESULT WINAPI
BindInfo_GetBindInfo(IInternetBindInfo
*iface
, DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
1221 CHECK_EXPECT(GetBindInfo
);
1223 ok(grfBINDF
!= NULL
, "grfBINDF == NULL\n");
1224 ok(pbindinfo
!= NULL
, "pbindinfo == NULL\n");
1225 ok(pbindinfo
->cbSize
== sizeof(BINDINFO
), "wrong size of pbindinfo: %ld\n", pbindinfo
->cbSize
);
1227 *grfBINDF
= BINDF_ASYNCHRONOUS
| BINDF_ASYNCSTORAGE
| BINDF_PULLDATA
| BINDF_FROMURLMON
| BINDF_NEEDFILE
;
1231 static HRESULT WINAPI
BindInfo_GetBindString(IInternetBindInfo
*iface
, ULONG ulStringType
, LPOLESTR
*ppwzStr
,
1232 ULONG cEl
, ULONG
*pcElFetched
)
1234 ok(0, "unexpected call\n");
1238 static IInternetBindInfoVtbl InternetBindInfoVtbl
= {
1239 BindInfo_QueryInterface
,
1242 BindInfo_GetBindInfo
,
1243 BindInfo_GetBindString
1246 static IInternetBindInfo bind_info
= {
1247 &InternetBindInfoVtbl
1250 static HRESULT WINAPI
ServiceProvider_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
1252 ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid
));
1254 return E_NOINTERFACE
;
1257 static ULONG WINAPI
ServiceProvider_AddRef(IServiceProvider
*iface
)
1262 static ULONG WINAPI
ServiceProvider_Release(IServiceProvider
*iface
)
1267 static HRESULT WINAPI
ServiceProvider_QueryService(IServiceProvider
*iface
, REFGUID guidService
,
1268 REFIID riid
, void **ppv
)
1270 if(IsEqualGUID(&CLSID_MimeEdit
, guidService
)) {
1272 return E_NOINTERFACE
;
1275 ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService
));
1279 static const IServiceProviderVtbl ServiceProviderVtbl
= {
1280 ServiceProvider_QueryInterface
,
1281 ServiceProvider_AddRef
,
1282 ServiceProvider_Release
,
1283 ServiceProvider_QueryService
1286 static IServiceProvider service_provider
= { &ServiceProviderVtbl
};
1288 static HRESULT WINAPI
ProtocolSink_QueryInterface(IInternetProtocolSink
*iface
, REFIID riid
, void **ppv
)
1290 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetProtocolSink
, riid
)) {
1295 if(IsEqualGUID(&IID_IServiceProvider
, riid
)) {
1296 *ppv
= &service_provider
;
1301 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid
));
1302 return E_NOINTERFACE
;
1305 static ULONG WINAPI
ProtocolSink_AddRef(IInternetProtocolSink
*iface
)
1310 static ULONG WINAPI
ProtocolSink_Release(IInternetProtocolSink
*iface
)
1315 static HRESULT WINAPI
ProtocolSink_Switch(IInternetProtocolSink
*iface
, PROTOCOLDATA
*pProtocolData
)
1317 ok(0, "unexpected call\n");
1321 static HRESULT WINAPI
ProtocolSink_ReportProgress(IInternetProtocolSink
*iface
, ULONG ulStatusCode
,
1322 const WCHAR
*szStatusText
)
1324 switch(ulStatusCode
) {
1325 case BINDSTATUS_MIMETYPEAVAILABLE
:
1326 CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
1327 ok(!lstrcmpW(szStatusText
, current_binding_test
->mime
), "status text %s\n", wine_dbgstr_w(szStatusText
));
1329 case BINDSTATUS_CACHEFILENAMEAVAILABLE
:
1330 CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
1333 ok(0, "unexpected call %lu %s\n", ulStatusCode
, wine_dbgstr_w(szStatusText
));
1339 static HRESULT WINAPI
ProtocolSink_ReportData(IInternetProtocolSink
*iface
, DWORD grfBSCF
, ULONG ulProgress
,
1340 ULONG ulProgressMax
)
1346 CHECK_EXPECT(ReportData
);
1348 ok(!ulProgress
, "ulProgress = %lu\n", ulProgress
);
1349 ok(ulProgress
== ulProgressMax
, "ulProgress != ulProgressMax\n");
1350 ok(grfBSCF
== (BSCF_FIRSTDATANOTIFICATION
| BSCF_INTERMEDIATEDATANOTIFICATION
1351 | BSCF_LASTDATANOTIFICATION
| BSCF_DATAFULLYAVAILABLE
| BSCF_AVAILABLEDATASIZEUNKNOWN
),
1352 "grcf = %08lx\n", grfBSCF
);
1354 hres
= IInternetProtocol_Read(current_binding_protocol
, buf
, sizeof(buf
), &read
);
1355 ok(hres
== S_OK
, "Read failed: %08lx\n", hres
);
1357 ok(!strcmp(buf
, current_binding_test
->data
), "unexpected data: %s\n", buf
);
1359 hres
= IInternetProtocol_Read(current_binding_protocol
, buf
, sizeof(buf
), &read
);
1360 ok(hres
== S_FALSE
, "Read failed: %08lx\n", hres
);
1364 static HRESULT WINAPI
ProtocolSink_ReportResult(IInternetProtocolSink
*iface
, HRESULT hrResult
, DWORD dwError
,
1367 CHECK_EXPECT(ReportResult
);
1368 ok(hrResult
== S_OK
, "hrResult = %08lx\n", hrResult
);
1369 ok(!dwError
, "dwError = %lu\n", dwError
);
1370 ok(!szResult
, "szResult = %s\n", wine_dbgstr_w(szResult
));
1374 static IInternetProtocolSinkVtbl InternetProtocolSinkVtbl
= {
1375 ProtocolSink_QueryInterface
,
1376 ProtocolSink_AddRef
,
1377 ProtocolSink_Release
,
1378 ProtocolSink_Switch
,
1379 ProtocolSink_ReportProgress
,
1380 ProtocolSink_ReportData
,
1381 ProtocolSink_ReportResult
1384 static IInternetProtocolSink protocol_sink
= { &InternetProtocolSinkVtbl
};
1386 static void test_mhtml_protocol_binding(const mhtml_binding_test_t
*test
)
1388 char file_name
[MAX_PATH
+32], *p
, urla
[INTERNET_MAX_URL_LENGTH
];
1389 WCHAR test_url
[INTERNET_MAX_URL_LENGTH
];
1390 IInternetProtocol
*protocol
;
1397 p
= file_name
+ GetCurrentDirectoryA(sizeof(file_name
), file_name
);
1399 strcpy(p
, "winetest.mht");
1401 file
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
1402 FILE_ATTRIBUTE_NORMAL
, NULL
);
1403 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFile failed\n");
1405 WriteFile(file
, test
->content
, strlen(test
->content
), &size
, NULL
);
1408 sprintf(urla
, test
->url
, file_name
);
1409 MultiByteToWideChar(CP_ACP
, 0, urla
, -1, test_url
, ARRAY_SIZE(test_url
));
1411 hres
= CoCreateInstance(&CLSID_IMimeHtmlProtocol
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IInternetProtocol
, (void**)&protocol
);
1412 ok(hres
== S_OK
, "Could not create protocol handler: %08lx\n", hres
);
1414 hres
= IInternetProtocol_QueryInterface(protocol
, &IID_IInternetProtocolEx
, (void**)&unk
);
1415 ok(hres
== E_NOINTERFACE
, "Could get IInternetProtocolEx\n");
1417 current_binding_test
= test
;
1418 current_binding_protocol
= protocol
;
1420 SET_EXPECT(GetBindInfo
);
1421 SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
1422 SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
1423 SET_EXPECT(ReportData
);
1424 SET_EXPECT(ReportResult
);
1425 hres
= IInternetProtocol_Start(protocol
, test_url
, &protocol_sink
, &bind_info
, 0, 0);
1426 ok(hres
== S_OK
, "Start failed: %08lx\n", hres
);
1427 CHECK_CALLED(GetBindInfo
);
1428 CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE
);
1429 todo_wine
CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE
);
1430 CHECK_CALLED(ReportData
);
1431 CHECK_CALLED(ReportResult
);
1433 IInternetProtocol_Release(protocol
);
1434 ret
= DeleteFileA("winetest.mht");
1435 ok(ret
, "DeleteFile failed: %lu\n", GetLastError());
1438 static const struct {
1439 const WCHAR
*base_url
;
1440 const WCHAR
*relative_url
;
1441 const WCHAR
*expected_result
;
1443 } combine_tests
[] = {
1445 L
"mhtml:file:///c:/dir/test.mht", L
"http://test.org",
1446 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org"
1448 L
"mhtml:file:///c:/dir/test.mht", L
"3D\"http://test.org\"",
1449 L
"mhtml:file:///c:/dir/test.mht!x-usc:3D\"http://test.org\""
1451 L
"mhtml:file:///c:/dir/test.mht", L
"123abc",
1452 L
"mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1454 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", L
"123abc",
1455 L
"mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1457 L
"MhtMl:file:///c:/dir/test.mht!x-usc:http://test.org/dir/dir2/file.html", L
"../..",
1458 L
"mhtml:file:///c:/dir/test.mht!x-usc:../.."
1460 L
"mhtml:file:///c:/dir/test.mht!x-usc:file:///c:/dir/dir2/file.html", L
"../..",
1461 L
"mhtml:file:///c:/dir/test.mht!x-usc:../.."
1463 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", L
"",
1464 L
"mhtml:file:///c:/dir/test.mht"
1466 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", L
"mhtml:file:///d:/file.html",
1467 L
"file:///d:/file.html", TRUE
1469 L
"mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", L
"mhtml:file:///c:/dir2/test.mht!x-usc:http://test.org",
1470 L
"mhtml:file:///c:/dir2/test.mht!x-usc:http://test.org", TRUE
1472 L
"mhtml:file:///c:/dir/test.mht!http://test.org", L
"123abc",
1473 L
"mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1475 L
"mhtml:file:///c:/dir/test.mht!http://test.org", L
"",
1476 L
"mhtml:file:///c:/dir/test.mht"
1480 static void test_mhtml_protocol_info(void)
1482 WCHAR combined_url
[INTERNET_MAX_URL_LENGTH
];
1483 IInternetProtocolInfo
*protocol_info
;
1488 hres
= CoCreateInstance(&CLSID_IMimeHtmlProtocol
, NULL
, CLSCTX_INPROC_SERVER
,
1489 &IID_IInternetProtocolInfo
, (void**)&protocol_info
);
1490 ok(hres
== S_OK
, "Could not create protocol info: %08lx\n", hres
);
1492 for(i
= 0; i
< ARRAY_SIZE(combine_tests
); i
++) {
1493 combined_len
= 0xdeadbeef;
1494 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, combine_tests
[i
].base_url
,
1495 combine_tests
[i
].relative_url
, ICU_BROWSER_MODE
,
1496 combined_url
, ARRAY_SIZE(combined_url
), &combined_len
, 0);
1497 todo_wine_if(combine_tests
[i
].todo
)
1498 ok(hres
== S_OK
, "[%u] CombineUrl failed: %08lx\n", i
, hres
);
1499 if(SUCCEEDED(hres
)) {
1500 exlen
= lstrlenW(combine_tests
[i
].expected_result
);
1501 ok(combined_len
== exlen
, "[%u] combined len is %lu, expected %u\n", i
, combined_len
, exlen
);
1502 ok(!lstrcmpW(combined_url
, combine_tests
[i
].expected_result
), "[%u] combined URL is %s, expected %s\n",
1503 i
, wine_dbgstr_w(combined_url
), wine_dbgstr_w(combine_tests
[i
].expected_result
));
1505 combined_len
= 0xdeadbeef;
1506 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, combine_tests
[i
].base_url
,
1507 combine_tests
[i
].relative_url
, ICU_BROWSER_MODE
,
1508 combined_url
, exlen
, &combined_len
, 0);
1509 ok(hres
== E_FAIL
, "[%u] CombineUrl returned: %08lx\n", i
, hres
);
1510 ok(!combined_len
, "[%u] combined_len = %lu\n", i
, combined_len
);
1514 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, L
"http://test.org", L
"http://test.org",
1515 ICU_BROWSER_MODE
, combined_url
, ARRAY_SIZE(combined_url
),
1517 ok(hres
== E_FAIL
, "CombineUrl failed: %08lx\n", hres
);
1519 IInternetProtocolInfo_Release(protocol_info
);
1522 static HRESULT WINAPI
outer_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
1524 ok(0, "unexpected call\n");
1525 return E_NOINTERFACE
;
1528 static ULONG WINAPI
outer_AddRef(IUnknown
*iface
)
1533 static ULONG WINAPI
outer_Release(IUnknown
*iface
)
1538 static const IUnknownVtbl outer_vtbl
= {
1539 outer_QueryInterface
,
1544 static BOOL broken_mhtml_resolver
;
1546 static void test_mhtml_protocol(void)
1548 IUnknown outer
= { &outer_vtbl
};
1549 IClassFactory
*class_factory
;
1550 IUnknown
*unk
, *unk2
;
1554 /* test class factory */
1555 hres
= CoGetClassObject(&CLSID_IMimeHtmlProtocol
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IUnknown
, (void**)&unk
);
1556 ok(hres
== S_OK
, "CoGetClassObject failed: %08lx\n", hres
);
1558 hres
= IUnknown_QueryInterface(unk
, &IID_IInternetProtocolInfo
, (void**)&unk2
);
1559 ok(hres
== E_NOINTERFACE
, "IInternetProtocolInfo supported\n");
1561 hres
= IUnknown_QueryInterface(unk
, &IID_IClassFactory
, (void**)&class_factory
);
1562 ok(hres
== S_OK
, "Could not get IClassFactory iface: %08lx\n", hres
);
1563 IUnknown_Release(unk
);
1565 hres
= IClassFactory_CreateInstance(class_factory
, &outer
, &IID_IUnknown
, (void**)&unk
);
1566 ok(hres
== S_OK
, "CreateInstance returned: %08lx\n", hres
);
1567 hres
= IUnknown_QueryInterface(unk
, &IID_IInternetProtocol
, (void**)&unk2
);
1568 ok(hres
== S_OK
, "Could not get IInternetProtocol iface: %08lx\n", hres
);
1569 IUnknown_Release(unk2
);
1570 IUnknown_Release(unk
);
1572 hres
= IClassFactory_CreateInstance(class_factory
, (IUnknown
*)0xdeadbeef, &IID_IInternetProtocol
, (void**)&unk2
);
1573 ok(hres
== CLASS_E_NOAGGREGATION
, "CreateInstance returned: %08lx\n", hres
);
1575 IClassFactory_Release(class_factory
);
1577 if(!broken_mhtml_resolver
)
1578 test_mhtml_protocol_info();
1580 for(i
= 0; i
< ARRAY_SIZE(binding_tests
); i
++)
1581 test_mhtml_protocol_binding(binding_tests
+ i
);
1584 static void test_MimeOleObjectFromMoniker(void)
1586 IMoniker
*mon
, *new_mon
;
1593 static const struct {
1595 const WCHAR
*mhtml_url
;
1597 {L
"file:///x:\\dir\\file.mht", L
"mhtml:file://x:\\dir\\file.mht"},
1598 {L
"file:///x:/dir/file.mht", L
"mhtml:file://x:\\dir\\file.mht"},
1599 {L
"http://www.winehq.org/index.html?query#hash", L
"mhtml:http://www.winehq.org/index.html?query#hash"},
1600 {L
"../test.mht", L
"mhtml:../test.mht"}
1603 for(i
= 0; i
< ARRAY_SIZE(tests
); i
++) {
1604 hres
= CreateURLMoniker(NULL
, tests
[i
].url
, &mon
);
1605 ok(hres
== S_OK
, "CreateURLMoniker failed: %08lx\n", hres
);
1607 hres
= CreateBindCtx(0, &bind_ctx
);
1608 ok(hres
== S_OK
, "CreateBindCtx failed: %08lx\n", hres
);
1610 hres
= MimeOleObjectFromMoniker(0, mon
, bind_ctx
, &IID_IUnknown
, (void**)&unk
, &new_mon
);
1611 ok(hres
== S_OK
|| broken(!i
&& hres
== INET_E_RESOURCE_NOT_FOUND
), "MimeOleObjectFromMoniker failed: %08lx\n", hres
);
1612 IBindCtx_Release(bind_ctx
);
1613 if(hres
== INET_E_RESOURCE_NOT_FOUND
) { /* winxp */
1614 win_skip("Broken MHTML behaviour found. Skipping some tests.\n");
1615 broken_mhtml_resolver
= TRUE
;
1619 hres
= IMoniker_GetDisplayName(new_mon
, NULL
, NULL
, &mhtml_url
);
1620 ok(hres
== S_OK
, "GetDisplayName failed: %08lx\n", hres
);
1621 ok(!lstrcmpW(mhtml_url
, tests
[i
].mhtml_url
), "[%d] unexpected mhtml URL: %s\n", i
, wine_dbgstr_w(mhtml_url
));
1622 CoTaskMemFree(mhtml_url
);
1624 IUnknown_Release(unk
);
1625 IMoniker_Release(new_mon
);
1626 IMoniker_Release(mon
);
1632 OleInitialize(NULL
);
1633 test_CreateVirtualStream();
1634 test_CreateSecurity();
1638 test_CreateMessage();
1639 test_MessageSetProp();
1640 test_MessageGetPropInfo();
1641 test_MessageOptions();
1642 test_BindToObject();
1643 test_BodyDeleteProp();
1644 test_MimeOleGetPropertySchema();
1645 test_mhtml_message();
1646 test_MimeOleObjectFromMoniker();
1647 test_mhtml_protocol();