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 WCHAR
*a2w(const char *str
)
123 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
124 ret
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
125 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
129 static int strcmp_wa(const WCHAR
*strw
, const char *stra
)
132 MultiByteToWideChar(CP_ACP
, 0, stra
, -1, buf
, sizeof(buf
)/sizeof(WCHAR
));
133 return lstrcmpW(strw
, buf
);
136 static void test_CreateVirtualStream(void)
141 hr
= MimeOleCreateVirtualStream(&pstm
);
142 ok(hr
== S_OK
, "ret %08x\n", hr
);
144 IStream_Release(pstm
);
147 static void test_CreateSecurity(void)
152 hr
= MimeOleCreateSecurity(&sec
);
153 ok(hr
== S_OK
, "ret %08x\n", hr
);
155 IMimeSecurity_Release(sec
);
158 static IStream
*create_stream_from_string(const char *data
)
164 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
);
165 ok(hr
== S_OK
, "ret %08x\n", hr
);
167 hr
= IStream_Write(stream
, data
, strlen(data
), NULL
);
168 ok(hr
== S_OK
, "Write failed: %08x\n", hr
);
171 hr
= IStream_Seek(stream
, off
, STREAM_SEEK_SET
, NULL
);
172 ok(hr
== S_OK
, "Seek failed: %08x\n", hr
);
177 #define test_current_encoding(a,b) _test_current_encoding(__LINE__,a,b)
178 static void _test_current_encoding(unsigned line
, IMimeBody
*mime_body
, ENCODINGTYPE encoding
)
180 ENCODINGTYPE current_encoding
;
183 hres
= IMimeBody_GetCurrentEncoding(mime_body
, ¤t_encoding
);
184 ok_(__FILE__
,line
)(hres
== S_OK
, "GetCurrentEncoding failed: %08x\n", hres
);
185 ok_(__FILE__
,line
)(current_encoding
== encoding
, "encoding = %d, expected %d\n", current_encoding
, encoding
);
188 static void test_CreateBody(void)
192 HBODY handle
= (void *)0xdeadbeef;
196 ULONG count
, found_param
, i
;
197 MIMEPARAMINFO
*param_info
;
198 IMimeAllocator
*alloc
;
202 hr
= CoCreateInstance(&CLSID_IMimeBody
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMimeBody
, (void**)&body
);
203 ok(hr
== S_OK
, "ret %08x\n", hr
);
205 hr
= IMimeBody_GetClassID(body
, NULL
);
206 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
208 hr
= IMimeBody_GetClassID(body
, &clsid
);
209 ok(hr
== S_OK
, "ret %08x\n", hr
);
210 ok(IsEqualGUID(&clsid
, &IID_IMimeBody
), "got %s\n", wine_dbgstr_guid(&clsid
));
212 hr
= IMimeBody_GetHandle(body
, &handle
);
213 ok(hr
== MIME_E_NO_DATA
, "ret %08x\n", hr
);
214 ok(handle
== NULL
, "handle %p\n", handle
);
216 in
= create_stream_from_string(msg1
);
218 /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
219 hr
= IMimeBody_InitNew(body
);
220 ok(hr
== S_OK
, "ret %08x\n", hr
);
222 test_current_encoding(body
, IET_7BIT
);
224 hr
= IMimeBody_Load(body
, in
);
225 ok(hr
== S_OK
, "ret %08x\n", hr
);
227 IStream_Seek(in
, off
, STREAM_SEEK_CUR
, &pos
);
228 ok(pos
.u
.LowPart
== 359, "pos %u\n", pos
.u
.LowPart
);
230 hr
= IMimeBody_IsContentType(body
, "multipart", "mixed");
231 ok(hr
== S_OK
, "ret %08x\n", hr
);
232 hr
= IMimeBody_IsContentType(body
, "text", "plain");
233 ok(hr
== S_FALSE
, "ret %08x\n", hr
);
234 hr
= IMimeBody_IsContentType(body
, NULL
, "mixed");
235 ok(hr
== S_OK
, "ret %08x\n", hr
);
236 hr
= IMimeBody_IsType(body
, IBT_EMPTY
);
237 ok(hr
== S_OK
, "got %08x\n", hr
);
239 hr
= IMimeBody_SetData(body
, IET_8BIT
, "text", "plain", &IID_IStream
, in
);
240 ok(hr
== S_OK
, "ret %08x\n", hr
);
241 hr
= IMimeBody_IsContentType(body
, "text", "plain");
243 ok(hr
== S_OK
, "ret %08x\n", hr
);
244 test_current_encoding(body
, IET_8BIT
);
246 memset(&offsets
, 0xcc, sizeof(offsets
));
247 hr
= IMimeBody_GetOffsets(body
, &offsets
);
248 ok(hr
== MIME_E_NO_DATA
, "ret %08x\n", hr
);
249 ok(offsets
.cbBoundaryStart
== 0, "got %d\n", offsets
.cbBoundaryStart
);
250 ok(offsets
.cbHeaderStart
== 0, "got %d\n", offsets
.cbHeaderStart
);
251 ok(offsets
.cbBodyStart
== 0, "got %d\n", offsets
.cbBodyStart
);
252 ok(offsets
.cbBodyEnd
== 0, "got %d\n", offsets
.cbBodyEnd
);
254 hr
= IMimeBody_IsType(body
, IBT_EMPTY
);
255 ok(hr
== S_FALSE
, "got %08x\n", hr
);
257 hr
= MimeOleGetAllocator(&alloc
);
258 ok(hr
== S_OK
, "ret %08x\n", hr
);
260 hr
= IMimeBody_GetParameters(body
, "nothere", &count
, ¶m_info
);
261 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
262 ok(count
== 0, "got %d\n", count
);
263 ok(!param_info
, "got %p\n", param_info
);
265 hr
= IMimeBody_GetParameters(body
, "bar", &count
, ¶m_info
);
266 ok(hr
== S_OK
, "ret %08x\n", hr
);
267 ok(count
== 0, "got %d\n", count
);
268 ok(!param_info
, "got %p\n", param_info
);
270 hr
= IMimeBody_GetParameters(body
, "Content-Type", &count
, ¶m_info
);
271 ok(hr
== S_OK
, "ret %08x\n", hr
);
272 todo_wine
/* native adds a charset parameter */
273 ok(count
== 4, "got %d\n", count
);
274 ok(param_info
!= NULL
, "got %p\n", param_info
);
277 for(i
= 0; i
< count
; i
++)
279 if(!strcmp(param_info
[i
].pszName
, "morestuff"))
282 ok(!strcmp(param_info
[i
].pszData
, "so\\me\"thing\""),
283 "got %s\n", param_info
[i
].pszData
);
285 else if(!strcmp(param_info
[i
].pszName
, "stuff"))
288 ok(!strcmp(param_info
[i
].pszData
, "du;nno"),
289 "got %s\n", param_info
[i
].pszData
);
292 ok(found_param
== 2, "matched %d params\n", found_param
);
294 hr
= IMimeAllocator_FreeParamInfoArray(alloc
, count
, param_info
, TRUE
);
295 ok(hr
== S_OK
, "ret %08x\n", hr
);
296 IMimeAllocator_Release(alloc
);
299 IMimeBody_Release(body
);
303 IStream IStream_iface
;
308 static inline TestStream
*impl_from_IStream(IStream
*iface
)
310 return CONTAINING_RECORD(iface
, TestStream
, IStream_iface
);
313 static HRESULT WINAPI
Stream_QueryInterface(IStream
*iface
, REFIID riid
, void **ppv
)
315 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_ISequentialStream
, riid
) || IsEqualGUID(&IID_IStream
, riid
)) {
320 ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid
));
322 return E_NOINTERFACE
;
325 static ULONG WINAPI
Stream_AddRef(IStream
*iface
)
327 TestStream
*This
= impl_from_IStream(iface
);
328 return InterlockedIncrement(&This
->ref
);
331 static ULONG WINAPI
Stream_Release(IStream
*iface
)
333 TestStream
*This
= impl_from_IStream(iface
);
334 ULONG ref
= InterlockedDecrement(&This
->ref
);
337 HeapFree(GetProcessHeap(), 0, This
);
342 static HRESULT WINAPI
Stream_Read(IStream
*iface
, void *pv
, ULONG cb
, ULONG
*pcbRead
)
344 TestStream
*This
= impl_from_IStream(iface
);
348 CHECK_EXPECT(Stream_Read
);
350 for(i
= 0; i
< cb
; i
++)
351 output
[i
] = '0' + This
->pos
++;
356 static HRESULT WINAPI
Stream_Write(IStream
*iface
, const void *pv
, ULONG cb
, ULONG
*pcbWritten
)
358 ok(0, "unexpected call\n");
362 static DWORD expect_seek_pos
;
364 static HRESULT WINAPI
Stream_Seek(IStream
*iface
, LARGE_INTEGER dlibMove
, DWORD dwOrigin
,
365 ULARGE_INTEGER
*plibNewPosition
)
367 TestStream
*This
= impl_from_IStream(iface
);
369 if(dwOrigin
== STREAM_SEEK_END
) {
370 CHECK_EXPECT(Stream_Seek_END
);
371 ok(dlibMove
.QuadPart
== expect_seek_pos
, "unexpected seek pos %u\n", dlibMove
.u
.LowPart
);
373 plibNewPosition
->QuadPart
= 10;
377 CHECK_EXPECT(Stream_Seek
);
379 ok(dlibMove
.QuadPart
== expect_seek_pos
, "unexpected seek pos %u\n", dlibMove
.u
.LowPart
);
380 ok(dwOrigin
== STREAM_SEEK_SET
, "dwOrigin = %d\n", dwOrigin
);
381 This
->pos
= dlibMove
.QuadPart
;
383 plibNewPosition
->QuadPart
= This
->pos
;
387 static HRESULT WINAPI
Stream_SetSize(IStream
*iface
, ULARGE_INTEGER libNewSize
)
389 ok(0, "unexpected call\n");
393 static HRESULT WINAPI
Stream_CopyTo(IStream
*iface
, IStream
*pstm
, ULARGE_INTEGER cb
,
394 ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
396 ok(0, "unexpected call\n");
400 static HRESULT WINAPI
Stream_Commit(IStream
*iface
, DWORD grfCommitFlags
)
402 ok(0, "unexpected call\n");
406 static HRESULT WINAPI
Stream_Revert(IStream
*iface
)
408 ok(0, "unexpected call\n");
412 static HRESULT WINAPI
Stream_LockRegion(IStream
*iface
, ULARGE_INTEGER libOffset
,
413 ULARGE_INTEGER cb
, DWORD dwLockType
)
415 ok(0, "unexpected call\n");
419 static HRESULT WINAPI
Stream_UnlockRegion(IStream
*iface
,
420 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
422 ok(0, "unexpected call\n");
426 static HRESULT WINAPI
Stream_Stat(IStream
*iface
, STATSTG
*pstatstg
, DWORD dwStatFlag
)
428 CHECK_EXPECT(Stream_Stat
);
429 ok(dwStatFlag
== STATFLAG_NONAME
, "dwStatFlag = %x\n", dwStatFlag
);
433 static HRESULT WINAPI
Stream_Clone(IStream
*iface
, IStream
**ppstm
)
435 ok(0, "unexpected call\n");
439 static const IStreamVtbl StreamVtbl
= {
440 Stream_QueryInterface
,
456 static IStream
*create_test_stream(void)
459 stream
= HeapAlloc(GetProcessHeap(), 0, sizeof(*stream
));
460 stream
->IStream_iface
.lpVtbl
= &StreamVtbl
;
463 return &stream
->IStream_iface
;
466 #define test_stream_read(a,b,c,d) _test_stream_read(__LINE__,a,b,c,d)
467 static void _test_stream_read(unsigned line
, IStream
*stream
, HRESULT exhres
, const char *exdata
, unsigned read_size
)
469 ULONG read
= 0xdeadbeed, exread
= strlen(exdata
);
474 read_size
= sizeof(buf
)-1;
476 hres
= IStream_Read(stream
, buf
, read_size
, &read
);
477 ok_(__FILE__
,line
)(hres
== exhres
, "Read returned %08x, expected %08x\n", hres
, exhres
);
478 ok_(__FILE__
,line
)(read
== exread
, "unexpected read size %u, expected %u\n", read
, exread
);
480 ok_(__FILE__
,line
)(read
== exread
&& !memcmp(buf
, exdata
, read
), "unexpected data %s\n", buf
);
483 static void test_SetData(void)
485 IStream
*stream
, *stream2
, *test_stream
;
489 hr
= CoCreateInstance(&CLSID_IMimeBody
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMimeBody
, (void**)&body
);
490 ok(hr
== S_OK
, "ret %08x\n", hr
);
492 /* Need to call InitNew before Load otherwise Load crashes with native inetcomm */
493 hr
= IMimeBody_InitNew(body
);
494 ok(hr
== S_OK
, "ret %08x\n", hr
);
496 stream
= create_stream_from_string(msg1
);
497 hr
= IMimeBody_Load(body
, stream
);
498 ok(hr
== S_OK
, "ret %08x\n", hr
);
499 IStream_Release(stream
);
501 test_stream
= create_test_stream();
502 hr
= IMimeBody_SetData(body
, IET_BINARY
, "text", "plain", &IID_IStream
, test_stream
);
504 ok(hr
== S_OK
, "ret %08x\n", hr
);
505 hr
= IMimeBody_IsContentType(body
, "text", "plain");
507 ok(hr
== S_OK
, "ret %08x\n", hr
);
509 test_current_encoding(body
, IET_BINARY
);
511 SET_EXPECT(Stream_Stat
);
512 SET_EXPECT(Stream_Seek_END
);
513 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
514 CHECK_CALLED(Stream_Stat
);
515 CHECK_CALLED(Stream_Seek_END
);
516 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
517 ok(stream
!= test_stream
, "unexpected stream\n");
519 SET_EXPECT(Stream_Seek
);
520 SET_EXPECT(Stream_Read
);
521 test_stream_read(stream
, S_OK
, "012", 3);
522 CHECK_CALLED(Stream_Seek
);
523 CHECK_CALLED(Stream_Read
);
525 SET_EXPECT(Stream_Stat
);
526 SET_EXPECT(Stream_Seek_END
);
527 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream2
);
528 CHECK_CALLED(Stream_Stat
);
529 CHECK_CALLED(Stream_Seek_END
);
530 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
531 ok(stream2
!= stream
, "unexpected stream\n");
533 SET_EXPECT(Stream_Seek
);
534 SET_EXPECT(Stream_Read
);
535 test_stream_read(stream2
, S_OK
, "01", 2);
536 CHECK_CALLED(Stream_Seek
);
537 CHECK_CALLED(Stream_Read
);
540 SET_EXPECT(Stream_Seek
);
541 SET_EXPECT(Stream_Read
);
542 test_stream_read(stream
, S_OK
, "345", 3);
543 CHECK_CALLED(Stream_Seek
);
544 CHECK_CALLED(Stream_Read
);
546 IStream_Release(stream
);
547 IStream_Release(stream2
);
548 IStream_Release(test_stream
);
550 stream
= create_stream_from_string(" \t\r\n|}~YWJj ZGV|}~mZw== \t"); /* "abcdefg" in base64 obscured by invalid chars */
551 hr
= IMimeBody_SetData(body
, IET_BASE64
, "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_BASE64
);
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
, "abc", 3);
561 test_stream_read(stream
, S_OK
, "defg", -1);
563 IStream_Release(stream
);
565 hr
= IMimeBody_GetData(body
, IET_BASE64
, &stream
);
566 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
568 test_stream_read(stream
, S_OK
, " \t\r", 3);
569 IStream_Release(stream
);
571 stream
= create_stream_from_string(" =3d=3D\"one\" \t=\r\ntw= o=\nx3\n=34\r\n5");
572 hr
= IMimeBody_SetData(body
, IET_QP
, "text", "plain", &IID_IStream
, stream
);
573 IStream_Release(stream
);
574 ok(hr
== S_OK
, "SetData failed: %08x\n", hr
);
576 test_current_encoding(body
, IET_QP
);
578 hr
= IMimeBody_GetData(body
, IET_BINARY
, &stream
);
579 ok(hr
== S_OK
, "GetData failed %08x\n", hr
);
581 test_stream_read(stream
, S_OK
, " ==\"one\" \ttw=o=3\n4\r\n5", -1);
583 IStream_Release(stream
);
585 IMimeBody_Release(body
);
588 static void test_Allocator(void)
591 IMimeAllocator
*alloc
;
593 hr
= MimeOleGetAllocator(&alloc
);
594 ok(hr
== S_OK
, "ret %08x\n", hr
);
595 IMimeAllocator_Release(alloc
);
598 static void test_CreateMessage(void)
608 FINDBODY find_struct
;
612 char text
[] = "text";
615 static const char att_pritype
[] = "att:pri-content-type";
617 hr
= MimeOleCreateMessage(NULL
, &msg
);
618 ok(hr
== S_OK
, "ret %08x\n", hr
);
620 stream
= create_stream_from_string(msg1
);
622 hr
= IMimeMessage_Load(msg
, stream
);
623 ok(hr
== S_OK
, "ret %08x\n", hr
);
625 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, TRUE
, &count
);
626 ok(hr
== S_OK
, "ret %08x\n", hr
);
627 ok(count
== 3, "got %d\n", count
);
629 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, FALSE
, &count
);
630 ok(hr
== S_OK
, "ret %08x\n", hr
);
631 ok(count
== 3, "got %d\n", count
);
633 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
634 ok(hr
== S_OK
, "ret %08x\n", hr
);
635 hr
= IMimeBody_GetOffsets(body
, &offsets
);
636 ok(hr
== S_OK
, "ret %08x\n", hr
);
637 ok(offsets
.cbBoundaryStart
== 0, "got %d\n", offsets
.cbBoundaryStart
);
638 ok(offsets
.cbHeaderStart
== 0, "got %d\n", offsets
.cbHeaderStart
);
639 ok(offsets
.cbBodyStart
== 359, "got %d\n", offsets
.cbBodyStart
);
640 ok(offsets
.cbBodyEnd
== 666, "got %d\n", offsets
.cbBodyEnd
);
641 IMimeBody_Release(body
);
643 hr
= IMimeMessage_GetBody(msg
, IBL_ROOT
, NULL
, &hbody
);
644 ok(hr
== S_OK
, "ret %08x\n", hr
);
646 hr
= IMimeBody_GetHandle(body
, NULL
);
647 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
649 hr
= IMimeBody_GetHandle(body
, &handle
);
650 ok(hr
== S_OK
, "ret %08x\n", hr
);
651 ok(handle
!= NULL
, "handle %p\n", handle
);
653 hr
= IMimeMessage_GetBody(msg
, IBL_PARENT
, hbody
, NULL
);
654 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
656 hbody2
= (HBODY
)0xdeadbeef;
657 hr
= IMimeMessage_GetBody(msg
, IBL_PARENT
, hbody
, &hbody2
);
658 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
659 ok(hbody2
== NULL
, "hbody2 %p\n", hbody2
);
661 PropVariantInit(&prop
);
662 hr
= IMimeMessage_GetBodyProp(msg
, hbody
, att_pritype
, 0, &prop
);
663 ok(hr
== S_OK
, "ret %08x\n", hr
);
664 ok(prop
.vt
== VT_LPSTR
, "vt %08x\n", prop
.vt
);
665 ok(!strcasecmp(prop
.u
.pszVal
, "multipart"), "got %s\n", prop
.u
.pszVal
);
666 PropVariantClear(&prop
);
668 hr
= IMimeMessage_GetBody(msg
, IBL_FIRST
, hbody
, &hbody
);
669 ok(hr
== S_OK
, "ret %08x\n", hr
);
670 hr
= IMimeMessage_BindToObject(msg
, hbody
, &IID_IMimeBody
, (void**)&body
);
671 ok(hr
== S_OK
, "ret %08x\n", hr
);
673 hr
= IMimeBody_GetHandle(body
, &handle
);
674 ok(hr
== S_OK
, "ret %08x\n", hr
);
675 ok(handle
== hbody
, "handle %p\n", handle
);
677 hr
= IMimeBody_GetOffsets(body
, &offsets
);
678 ok(hr
== S_OK
, "ret %08x\n", hr
);
679 ok(offsets
.cbBoundaryStart
== 405, "got %d\n", offsets
.cbBoundaryStart
);
680 ok(offsets
.cbHeaderStart
== 428, "got %d\n", offsets
.cbHeaderStart
);
681 ok(offsets
.cbBodyStart
== 518, "got %d\n", offsets
.cbBodyStart
);
682 ok(offsets
.cbBodyEnd
== 523, "got %d\n", offsets
.cbBodyEnd
);
684 hr
= IMimeBody_GetCharset(body
, &hcs
);
685 ok(hr
== S_OK
, "ret %08x\n", hr
);
688 ok(hcs
!= NULL
, "Expected non-NULL charset\n");
691 IMimeBody_Release(body
);
693 hr
= IMimeMessage_GetBody(msg
, IBL_NEXT
, hbody
, &hbody
);
694 ok(hr
== S_OK
, "ret %08x\n", hr
);
695 hr
= IMimeMessage_BindToObject(msg
, hbody
, &IID_IMimeBody
, (void**)&body
);
696 ok(hr
== S_OK
, "ret %08x\n", hr
);
698 hr
= IMimeBody_GetHandle(body
, &handle
);
699 ok(hr
== S_OK
, "ret %08x\n", hr
);
700 ok(handle
== hbody
, "handle %p\n", handle
);
702 hr
= IMimeBody_GetOffsets(body
, &offsets
);
703 ok(hr
== S_OK
, "ret %08x\n", hr
);
704 ok(offsets
.cbBoundaryStart
== 525, "got %d\n", offsets
.cbBoundaryStart
);
705 ok(offsets
.cbHeaderStart
== 548, "got %d\n", offsets
.cbHeaderStart
);
706 ok(offsets
.cbBodyStart
== 629, "got %d\n", offsets
.cbBodyStart
);
707 ok(offsets
.cbBodyEnd
== 639, "got %d\n", offsets
.cbBodyEnd
);
708 IMimeBody_Release(body
);
710 find_struct
.pszPriType
= text
;
711 find_struct
.pszSubType
= NULL
;
713 hr
= IMimeMessage_FindFirst(msg
, &find_struct
, &hbody
);
714 ok(hr
== S_OK
, "ret %08x\n", hr
);
716 hr
= IMimeMessage_FindNext(msg
, &find_struct
, &hbody
);
717 ok(hr
== S_OK
, "ret %08x\n", hr
);
719 hr
= IMimeMessage_FindNext(msg
, &find_struct
, &hbody
);
720 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
722 hr
= IMimeMessage_GetAttachments(msg
, &count
, &body_list
);
723 ok(hr
== S_OK
, "ret %08x\n", hr
);
724 ok(count
== 2, "got %d\n", count
);
727 IMimeBody
*attachment
;
730 PropVariantInit(&prop
);
732 hr
= IMimeMessage_BindToObject(msg
, body_list
[0], &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_8BIT
);
741 hr
= IMimeBody_GetProp(attachment
, "Content-Transfer-Encoding", 0, &prop
);
742 ok(hr
== S_OK
, "ret %08x\n", hr
);
744 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
745 ok(!strcmp(prop
.u
.pszVal
, "8bit"), "got %s\n", prop
.u
.pszVal
);
746 PropVariantClear(&prop
);
748 hr
= IMimeBody_IsType(attachment
, IBT_ATTACHMENT
);
749 todo_wine
ok(hr
== S_FALSE
, "ret %08x\n", hr
);
751 IMimeBody_Release(attachment
);
753 hr
= IMimeMessage_BindToObject(msg
, body_list
[1], &IID_IMimeBody
, (void**)&attachment
);
754 ok(hr
== S_OK
, "ret %08x\n", hr
);
756 hr
= IMimeBody_IsContentType(attachment
, "multipart", NULL
);
757 ok(hr
== S_FALSE
, "ret %08x\n", hr
);
759 test_current_encoding(attachment
, IET_7BIT
);
762 hr
= IMimeBody_GetProp(attachment
, "Content-Transfer-Encoding", 0, &prop
);
763 ok(hr
== S_OK
, "ret %08x\n", hr
);
764 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
765 ok(!strcmp(prop
.u
.pszVal
, "7bit"), "got %s\n", prop
.u
.pszVal
);
766 PropVariantClear(&prop
);
768 hr
= IMimeBody_IsType(attachment
, IBT_ATTACHMENT
);
769 ok(hr
== S_OK
, "ret %08x\n", hr
);
771 IMimeBody_Release(attachment
);
773 CoTaskMemFree(body_list
);
775 hr
= IMimeBody_GetCharset(body
, &hcs
);
776 ok(hr
== S_OK
, "ret %08x\n", hr
);
779 ok(hcs
!= NULL
, "Expected non-NULL charset\n");
782 IMimeMessage_Release(msg
);
784 ref
= IStream_AddRef(stream
);
786 broken(ref
== 1), /* win95 */
788 IStream_Release(stream
);
790 IStream_Release(stream
);
793 static void test_mhtml_message(void)
795 IMimeMessage
*mime_message
;
796 IMimeBody
*mime_body
;
802 hres
= MimeOleCreateMessage(NULL
, &mime_message
);
803 ok(hres
== S_OK
, "MimeOleCreateMessage failed: %08x\n", hres
);
805 stream
= create_stream_from_string(mhtml_page1
);
806 hres
= IMimeMessage_Load(mime_message
, stream
);
807 IStream_Release(stream
);
808 ok(hres
== S_OK
, "Load failed: %08x\n", hres
);
810 hres
= IMimeMessage_CountBodies(mime_message
, HBODY_ROOT
, TRUE
, &count
);
811 ok(hres
== S_OK
, "CountBodies failed: %08x\n", hres
);
812 ok(count
== 3, "got %d\n", count
);
814 hres
= IMimeMessage_GetAttachments(mime_message
, &count
, &body_list
);
815 ok(hres
== S_OK
, "GetAttachments failed: %08x\n", hres
);
816 ok(count
== 2, "count = %u\n", count
);
818 hres
= IMimeMessage_BindToObject(mime_message
, body_list
[0], &IID_IMimeBody
, (void**)&mime_body
);
819 ok(hres
== S_OK
, "BindToObject failed: %08x\n", hres
);
821 hres
= IMimeBody_GetData(mime_body
, IET_BINARY
, &stream
);
822 ok(hres
== S_OK
, "GetData failed: %08x\n", hres
);
823 test_stream_read(stream
, S_OK
, "<HTML></HTML>", -1);
824 IStream_Release(stream
);
826 test_current_encoding(mime_body
, IET_QP
);
828 IMimeBody_Release(mime_body
);
830 hres
= IMimeMessage_BindToObject(mime_message
, body_list
[1], &IID_IMimeBody
, (void**)&mime_body
);
831 ok(hres
== S_OK
, "BindToObject failed: %08x\n", hres
);
833 test_current_encoding(mime_body
, IET_BASE64
);
835 hres
= IMimeBody_GetData(mime_body
, IET_BINARY
, &stream
);
836 ok(hres
== S_OK
, "GetData failed: %08x\n", hres
);
837 test_stream_read(stream
, S_OK
, "Test", -1);
838 IStream_Release(stream
);
840 IMimeBody_Release(mime_body
);
842 CoTaskMemFree(body_list
);
844 IMimeMessage_Release(mime_message
);
847 static void test_MessageSetProp(void)
849 static const char topic
[] = "wine topic";
850 static const WCHAR topicW
[] = {'w','i','n','e',' ','t','o','p','i','c',0};
856 hr
= MimeOleCreateMessage(NULL
, &msg
);
857 ok(hr
== S_OK
, "ret %08x\n", hr
);
859 PropVariantInit(&prop
);
861 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
862 ok(hr
== S_OK
, "ret %08x\n", hr
);
864 hr
= IMimeBody_SetProp(body
, NULL
, 0, &prop
);
865 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
867 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, NULL
);
868 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
871 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
872 strcpy(prop
.u
.pszVal
, topic
);
873 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, &prop
);
874 ok(hr
== S_OK
, "ret %08x\n", hr
);
875 PropVariantClear(&prop
);
877 hr
= IMimeBody_GetProp(body
, NULL
, 0, &prop
);
878 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
880 hr
= IMimeBody_GetProp(body
, "Thread-Topic", 0, NULL
);
881 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
883 hr
= IMimeBody_GetProp(body
, "Wine-Topic", 0, &prop
);
884 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
887 hr
= IMimeBody_GetProp(body
, "Thread-Topic", 0, &prop
);
888 ok(hr
== S_OK
, "ret %08x\n", hr
);
891 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
892 ok(!strcmp(prop
.u
.pszVal
, topic
), "got %s\n", prop
.u
.pszVal
);
893 PropVariantClear(&prop
);
897 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
898 strcpy(prop
.u
.pszVal
, topic
);
899 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
900 ok(hr
== S_OK
, "ret %08x\n", hr
);
901 PropVariantClear(&prop
);
904 hr
= IMimeBody_GetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
905 ok(hr
== S_OK
, "ret %08x\n", hr
);
908 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
909 ok(!strcmp(prop
.u
.pszVal
, topic
), "got %s\n", prop
.u
.pszVal
);
910 PropVariantClear(&prop
);
913 /* Using the name or PID returns the same result. */
915 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
916 ok(hr
== S_OK
, "ret %08x\n", hr
);
919 ok(prop
.vt
== VT_LPSTR
, "type %d\n", prop
.vt
);
920 ok(!strcmp(prop
.u
.pszVal
, topic
), "got %s\n", prop
.u
.pszVal
);
921 PropVariantClear(&prop
);
925 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
926 ok(hr
== S_OK
, "ret %08x\n", hr
);
929 ok(prop
.vt
== VT_LPWSTR
, "type %d\n", prop
.vt
);
930 ok(!lstrcmpW(prop
.u
.pwszVal
, topicW
), "got %s\n", wine_dbgstr_w(prop
.u
.pwszVal
));
931 PropVariantClear(&prop
);
935 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
936 strcpy(prop
.u
.pszVal
, topic
);
937 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_TO
), 0, &prop
);
938 ok(hr
== S_OK
, "ret %08x\n", hr
);
939 PropVariantClear(&prop
);
941 /* Out of Range PID */
943 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
944 strcpy(prop
.u
.pszVal
, topic
);
945 hr
= IMimeBody_SetProp(body
, PIDTOSTR(124), 0, &prop
);
946 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
947 PropVariantClear(&prop
);
949 IMimeBody_Release(body
);
950 IMimeMessage_Release(msg
);
953 static void test_MessageGetPropInfo(void)
955 static const char topic
[] = "wine topic";
956 static const char subject
[] = "wine testing";
963 hr
= MimeOleCreateMessage(NULL
, &msg
);
964 ok(hr
== S_OK
, "ret %08x\n", hr
);
966 PropVariantInit(&prop
);
968 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
969 ok(hr
== S_OK
, "ret %08x\n", hr
);
972 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
973 strcpy(prop
.u
.pszVal
, topic
);
974 hr
= IMimeBody_SetProp(body
, "Thread-Topic", 0, &prop
);
975 ok(hr
== S_OK
, "ret %08x\n", hr
);
976 PropVariantClear(&prop
);
979 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(subject
)+1);
980 strcpy(prop
.u
.pszVal
, subject
);
981 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
982 ok(hr
== S_OK
, "ret %08x\n", hr
);
983 PropVariantClear(&prop
);
985 memset(&info
, 0, sizeof(info
));
986 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
987 hr
= IMimeBody_GetPropInfo(body
, NULL
, &info
);
988 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
990 memset(&info
, 0, sizeof(info
));
991 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
992 hr
= IMimeBody_GetPropInfo(body
, "Subject", NULL
);
993 ok(hr
== E_INVALIDARG
, "ret %08x\n", hr
);
995 memset(&info
, 0xfe, sizeof(info
));
996 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
997 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
998 ok(hr
== S_OK
, "ret %08x\n", hr
);
1001 ok(info
.dwMask
& (PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
), "Invalid mask 0x%08x\n", info
.dwFlags
);
1002 todo_wine
ok(info
.dwFlags
& 0x10000000, "Invalid flags 0x%08x\n", info
.dwFlags
);
1003 ok(info
.ietEncoding
== 0, "Invalid encoding %d\n", info
.ietEncoding
);
1004 ok(info
.dwPropId
== PID_HDR_SUBJECT
, "Invalid propid %d\n", info
.dwPropId
);
1005 ok(info
.cValues
== 0xfefefefe, "Invalid cValues %d\n", info
.cValues
);
1008 memset(&info
, 0xfe, sizeof(info
));
1010 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
1011 ok(hr
== S_OK
, "ret %08x\n", hr
);
1014 ok(info
.dwMask
== 0, "Invalid mask 0x%08x\n", info
.dwFlags
);
1015 ok(info
.dwFlags
== 0xfefefefe, "Invalid flags 0x%08x\n", info
.dwFlags
);
1016 ok(info
.ietEncoding
== -16843010, "Invalid encoding %d\n", info
.ietEncoding
);
1017 ok(info
.dwPropId
== -16843010, "Invalid propid %d\n", info
.dwPropId
);
1020 memset(&info
, 0xfe, sizeof(info
));
1022 info
.dwPropId
= 1024;
1023 info
.ietEncoding
= 99;
1024 hr
= IMimeBody_GetPropInfo(body
, "Subject", &info
);
1025 ok(hr
== S_OK
, "ret %08x\n", hr
);
1028 ok(info
.dwMask
== 0, "Invalid mask 0x%08x\n", info
.dwFlags
);
1029 ok(info
.dwFlags
== 0xfefefefe, "Invalid flags 0x%08x\n", info
.dwFlags
);
1030 ok(info
.ietEncoding
== 99, "Invalid encoding %d\n", info
.ietEncoding
);
1031 ok(info
.dwPropId
== 1024, "Invalid propid %d\n", info
.dwPropId
);
1034 memset(&info
, 0, sizeof(info
));
1035 info
.dwMask
= PIM_ENCODINGTYPE
| PIM_FLAGS
| PIM_PROPID
;
1036 hr
= IMimeBody_GetPropInfo(body
, "Invalid Property", &info
);
1037 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1039 IMimeBody_Release(body
);
1040 IMimeMessage_Release(msg
);
1043 static void test_MessageOptions(void)
1045 static const char string
[] = "XXXXX";
1046 static const char zero
[] = "0";
1051 hr
= MimeOleCreateMessage(NULL
, &msg
);
1052 ok(hr
== S_OK
, "ret %08x\n", hr
);
1054 PropVariantInit(&prop
);
1057 prop
.u
.boolVal
= TRUE
;
1058 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1059 ok(hr
== S_OK
, "ret %08x\n", hr
);
1060 PropVariantClear(&prop
);
1062 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1063 todo_wine
ok(hr
== S_OK
, "ret %08x\n", hr
);
1064 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1065 todo_wine
ok(prop
.u
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.u
.boolVal
);
1066 PropVariantClear(&prop
);
1069 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(string
)+1);
1070 strcpy(prop
.u
.pszVal
, string
);
1071 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1072 ok(hr
== S_OK
, "ret %08x\n", hr
);
1073 PropVariantClear(&prop
);
1075 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1076 todo_wine
ok(hr
== S_OK
, "ret %08x\n", hr
);
1077 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1078 todo_wine
ok(prop
.u
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.u
.boolVal
);
1079 PropVariantClear(&prop
);
1081 /* Invalid property type doesn't change the value */
1083 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(zero
)+1);
1084 strcpy(prop
.u
.pszVal
, zero
);
1085 hr
= IMimeMessage_SetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1086 ok(hr
== S_OK
, "ret %08x\n", hr
);
1087 PropVariantClear(&prop
);
1089 hr
= IMimeMessage_GetOption(msg
, OID_HIDE_TNEF_ATTACHMENTS
, &prop
);
1090 todo_wine
ok(hr
== S_OK
, "ret %08x\n", hr
);
1091 todo_wine
ok(prop
.vt
== VT_BOOL
, "vt %08x\n", prop
.vt
);
1092 todo_wine
ok(prop
.u
.boolVal
== TRUE
, "Hide Attachments got %d\n", prop
.u
.boolVal
);
1093 PropVariantClear(&prop
);
1097 prop
.u
.boolVal
= TRUE
;
1098 hr
= IMimeMessage_SetOption(msg
, 0xff00000a, &prop
);
1099 ok(hr
== MIME_E_INVALID_OPTION_ID
, "ret %08x\n", hr
);
1100 PropVariantClear(&prop
);
1102 /* Out of range before type. */
1105 hr
= IMimeMessage_SetOption(msg
, 0xff00000a, &prop
);
1106 ok(hr
== MIME_E_INVALID_OPTION_ID
, "ret %08x\n", hr
);
1107 PropVariantClear(&prop
);
1109 IMimeMessage_Release(msg
);
1112 static void test_BindToObject(void)
1119 hr
= MimeOleCreateMessage(NULL
, &msg
);
1120 ok(hr
== S_OK
, "ret %08x\n", hr
);
1122 hr
= IMimeMessage_CountBodies(msg
, HBODY_ROOT
, TRUE
, &count
);
1123 ok(hr
== S_OK
, "ret %08x\n", hr
);
1124 ok(count
== 1, "got %d\n", count
);
1126 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
1127 ok(hr
== S_OK
, "ret %08x\n", hr
);
1128 IMimeBody_Release(body
);
1130 IMimeMessage_Release(msg
);
1133 static void test_BodyDeleteProp(void)
1135 static const char topic
[] = "wine topic";
1141 hr
= MimeOleCreateMessage(NULL
, &msg
);
1142 ok(hr
== S_OK
, "ret %08x\n", hr
);
1144 PropVariantInit(&prop
);
1146 hr
= IMimeMessage_BindToObject(msg
, HBODY_ROOT
, &IID_IMimeBody
, (void**)&body
);
1147 ok(hr
== S_OK
, "ret %08x\n", hr
);
1149 hr
= IMimeBody_DeleteProp(body
, "Subject");
1150 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1152 hr
= IMimeBody_DeleteProp(body
, PIDTOSTR(PID_HDR_SUBJECT
));
1153 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1156 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
1157 strcpy(prop
.u
.pszVal
, topic
);
1158 hr
= IMimeBody_SetProp(body
, "Subject", 0, &prop
);
1159 ok(hr
== S_OK
, "ret %08x\n", hr
);
1160 PropVariantClear(&prop
);
1162 hr
= IMimeBody_DeleteProp(body
, "Subject");
1163 ok(hr
== S_OK
, "ret %08x\n", hr
);
1165 hr
= IMimeBody_GetProp(body
, "Subject", 0, &prop
);
1166 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1169 prop
.u
.pszVal
= CoTaskMemAlloc(strlen(topic
)+1);
1170 strcpy(prop
.u
.pszVal
, topic
);
1171 hr
= IMimeBody_SetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
1172 ok(hr
== S_OK
, "ret %08x\n", hr
);
1173 PropVariantClear(&prop
);
1175 hr
= IMimeBody_DeleteProp(body
, PIDTOSTR(PID_HDR_SUBJECT
));
1176 ok(hr
== S_OK
, "ret %08x\n", hr
);
1178 hr
= IMimeBody_GetProp(body
, PIDTOSTR(PID_HDR_SUBJECT
), 0, &prop
);
1179 ok(hr
== MIME_E_NOT_FOUND
, "ret %08x\n", hr
);
1181 IMimeBody_Release(body
);
1182 IMimeMessage_Release(msg
);
1185 static void test_MimeOleGetPropertySchema(void)
1188 IMimePropertySchema
*schema
= NULL
;
1190 hr
= MimeOleGetPropertySchema(&schema
);
1191 ok(hr
== S_OK
, "ret %08x\n", hr
);
1193 IMimePropertySchema_Release(schema
);
1198 const char *content
;
1201 } mhtml_binding_test_t
;
1203 static const mhtml_binding_test_t binding_tests
[] = {
1211 "mhtml:file://%s!http://winehq.org/mhtmltest.html",
1218 static const mhtml_binding_test_t
*current_binding_test
;
1219 static IInternetProtocol
*current_binding_protocol
;
1221 static HRESULT WINAPI
BindInfo_QueryInterface(IInternetBindInfo
*iface
, REFIID riid
, void **ppv
)
1223 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetBindInfo
, riid
)) {
1229 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid
));
1230 return E_NOINTERFACE
;
1233 static ULONG WINAPI
BindInfo_AddRef(IInternetBindInfo
*iface
)
1238 static ULONG WINAPI
BindInfo_Release(IInternetBindInfo
*iface
)
1243 static HRESULT WINAPI
BindInfo_GetBindInfo(IInternetBindInfo
*iface
, DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
1245 CHECK_EXPECT(GetBindInfo
);
1247 ok(grfBINDF
!= NULL
, "grfBINDF == NULL\n");
1248 ok(pbindinfo
!= NULL
, "pbindinfo == NULL\n");
1249 ok(pbindinfo
->cbSize
== sizeof(BINDINFO
), "wrong size of pbindinfo: %d\n", pbindinfo
->cbSize
);
1251 *grfBINDF
= BINDF_ASYNCHRONOUS
| BINDF_ASYNCSTORAGE
| BINDF_PULLDATA
| BINDF_FROMURLMON
| BINDF_NEEDFILE
;
1255 static HRESULT WINAPI
BindInfo_GetBindString(IInternetBindInfo
*iface
, ULONG ulStringType
, LPOLESTR
*ppwzStr
,
1256 ULONG cEl
, ULONG
*pcElFetched
)
1258 ok(0, "unexpected call\n");
1262 static IInternetBindInfoVtbl InternetBindInfoVtbl
= {
1263 BindInfo_QueryInterface
,
1266 BindInfo_GetBindInfo
,
1267 BindInfo_GetBindString
1270 static IInternetBindInfo bind_info
= {
1271 &InternetBindInfoVtbl
1274 static HRESULT WINAPI
ServiceProvider_QueryInterface(IServiceProvider
*iface
, REFIID riid
, void **ppv
)
1276 ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid
));
1278 return E_NOINTERFACE
;
1281 static ULONG WINAPI
ServiceProvider_AddRef(IServiceProvider
*iface
)
1286 static ULONG WINAPI
ServiceProvider_Release(IServiceProvider
*iface
)
1291 static HRESULT WINAPI
ServiceProvider_QueryService(IServiceProvider
*iface
, REFGUID guidService
,
1292 REFIID riid
, void **ppv
)
1294 if(IsEqualGUID(&CLSID_MimeEdit
, guidService
)) {
1296 return E_NOINTERFACE
;
1299 ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService
));
1303 static const IServiceProviderVtbl ServiceProviderVtbl
= {
1304 ServiceProvider_QueryInterface
,
1305 ServiceProvider_AddRef
,
1306 ServiceProvider_Release
,
1307 ServiceProvider_QueryService
1310 static IServiceProvider service_provider
= { &ServiceProviderVtbl
};
1312 static HRESULT WINAPI
ProtocolSink_QueryInterface(IInternetProtocolSink
*iface
, REFIID riid
, void **ppv
)
1314 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetProtocolSink
, riid
)) {
1319 if(IsEqualGUID(&IID_IServiceProvider
, riid
)) {
1320 *ppv
= &service_provider
;
1325 ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid
));
1326 return E_NOINTERFACE
;
1329 static ULONG WINAPI
ProtocolSink_AddRef(IInternetProtocolSink
*iface
)
1334 static ULONG WINAPI
ProtocolSink_Release(IInternetProtocolSink
*iface
)
1339 static HRESULT WINAPI
ProtocolSink_Switch(IInternetProtocolSink
*iface
, PROTOCOLDATA
*pProtocolData
)
1341 ok(0, "unexpected call\n");
1345 static HRESULT WINAPI
ProtocolSink_ReportProgress(IInternetProtocolSink
*iface
, ULONG ulStatusCode
,
1346 const WCHAR
*szStatusText
)
1348 switch(ulStatusCode
) {
1349 case BINDSTATUS_MIMETYPEAVAILABLE
:
1350 CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
1351 ok(!strcmp_wa(szStatusText
, current_binding_test
->mime
), "status text %s\n", wine_dbgstr_w(szStatusText
));
1353 case BINDSTATUS_CACHEFILENAMEAVAILABLE
:
1354 CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
1357 ok(0, "unexpected call %u %s\n", ulStatusCode
, wine_dbgstr_w(szStatusText
));
1363 static HRESULT WINAPI
ProtocolSink_ReportData(IInternetProtocolSink
*iface
, DWORD grfBSCF
, ULONG ulProgress
,
1364 ULONG ulProgressMax
)
1370 CHECK_EXPECT(ReportData
);
1372 ok(!ulProgress
, "ulProgress = %u\n", ulProgress
);
1373 ok(ulProgress
== ulProgressMax
, "ulProgress != ulProgressMax\n");
1374 ok(grfBSCF
== (BSCF_FIRSTDATANOTIFICATION
| BSCF_INTERMEDIATEDATANOTIFICATION
1375 | BSCF_LASTDATANOTIFICATION
| BSCF_DATAFULLYAVAILABLE
| BSCF_AVAILABLEDATASIZEUNKNOWN
),
1376 "grcf = %08x\n", grfBSCF
);
1378 hres
= IInternetProtocol_Read(current_binding_protocol
, buf
, sizeof(buf
), &read
);
1379 ok(hres
== S_OK
, "Read failed: %08x\n", hres
);
1381 ok(!strcmp(buf
, current_binding_test
->data
), "unexpected data: %s\n", buf
);
1383 hres
= IInternetProtocol_Read(current_binding_protocol
, buf
, sizeof(buf
), &read
);
1384 ok(hres
== S_FALSE
, "Read failed: %08x\n", hres
);
1388 static HRESULT WINAPI
ProtocolSink_ReportResult(IInternetProtocolSink
*iface
, HRESULT hrResult
, DWORD dwError
,
1391 CHECK_EXPECT(ReportResult
);
1392 ok(hrResult
== S_OK
, "hrResult = %08x\n", hrResult
);
1393 ok(!dwError
, "dwError = %u\n", dwError
);
1394 ok(!szResult
, "szResult = %s\n", wine_dbgstr_w(szResult
));
1398 static IInternetProtocolSinkVtbl InternetProtocolSinkVtbl
= {
1399 ProtocolSink_QueryInterface
,
1400 ProtocolSink_AddRef
,
1401 ProtocolSink_Release
,
1402 ProtocolSink_Switch
,
1403 ProtocolSink_ReportProgress
,
1404 ProtocolSink_ReportData
,
1405 ProtocolSink_ReportResult
1408 static IInternetProtocolSink protocol_sink
= { &InternetProtocolSinkVtbl
};
1410 static void test_mhtml_protocol_binding(const mhtml_binding_test_t
*test
)
1412 char file_name
[MAX_PATH
+32], *p
, urla
[INTERNET_MAX_URL_LENGTH
];
1413 WCHAR test_url
[INTERNET_MAX_URL_LENGTH
];
1414 IInternetProtocol
*protocol
;
1421 p
= file_name
+ GetCurrentDirectoryA(sizeof(file_name
), file_name
);
1423 strcpy(p
, "winetest.mht");
1425 file
= CreateFileA(file_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
1426 FILE_ATTRIBUTE_NORMAL
, NULL
);
1427 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFile failed\n");
1429 WriteFile(file
, test
->content
, strlen(test
->content
), &size
, NULL
);
1432 sprintf(urla
, test
->url
, file_name
);
1433 MultiByteToWideChar(CP_ACP
, 0, urla
, -1, test_url
, sizeof(test_url
)/sizeof(WCHAR
));
1435 hres
= CoCreateInstance(&CLSID_IMimeHtmlProtocol
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IInternetProtocol
, (void**)&protocol
);
1436 ok(hres
== S_OK
, "Could not create protocol handler: %08x\n", hres
);
1438 hres
= IInternetProtocol_QueryInterface(protocol
, &IID_IInternetProtocolEx
, (void**)&unk
);
1439 ok(hres
== E_NOINTERFACE
, "Could get IInternetProtocolEx\n");
1441 current_binding_test
= test
;
1442 current_binding_protocol
= protocol
;
1444 SET_EXPECT(GetBindInfo
);
1445 SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE
);
1446 SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE
);
1447 SET_EXPECT(ReportData
);
1448 SET_EXPECT(ReportResult
);
1449 hres
= IInternetProtocol_Start(protocol
, test_url
, &protocol_sink
, &bind_info
, 0, 0);
1450 ok(hres
== S_OK
, "Start failed: %08x\n", hres
);
1451 CHECK_CALLED(GetBindInfo
);
1452 CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE
);
1453 todo_wine
CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE
);
1454 CHECK_CALLED(ReportData
);
1455 CHECK_CALLED(ReportResult
);
1457 IInternetProtocol_Release(protocol
);
1458 ret
= DeleteFileA("winetest.mht");
1459 ok(ret
, "DeleteFile failed: %u\n", GetLastError());
1462 static const struct {
1463 const char *base_url
;
1464 const char *relative_url
;
1465 const char *expected_result
;
1467 } combine_tests
[] = {
1469 "mhtml:file:///c:/dir/test.mht", "http://test.org",
1470 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org"
1472 "mhtml:file:///c:/dir/test.mht", "3D\"http://test.org\"",
1473 "mhtml:file:///c:/dir/test.mht!x-usc:3D\"http://test.org\""
1475 "mhtml:file:///c:/dir/test.mht", "123abc",
1476 "mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1478 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "123abc",
1479 "mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1481 "MhtMl:file:///c:/dir/test.mht!x-usc:http://test.org/dir/dir2/file.html", "../..",
1482 "mhtml:file:///c:/dir/test.mht!x-usc:../.."
1483 }, {"mhtml:file:///c:/dir/test.mht!x-usc:file:///c:/dir/dir2/file.html", "../..",
1484 "mhtml:file:///c:/dir/test.mht!x-usc:../.."
1486 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "",
1487 "mhtml:file:///c:/dir/test.mht"
1489 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "mhtml:file:///d:/file.html",
1490 "file:///d:/file.html", TRUE
1492 "mhtml:file:///c:/dir/test.mht!x-usc:http://test.org", "mhtml:file:///c:/dir2/test.mht!x-usc:http://test.org",
1493 "mhtml:file:///c:/dir2/test.mht!x-usc:http://test.org", TRUE
1495 "mhtml:file:///c:/dir/test.mht!http://test.org", "123abc",
1496 "mhtml:file:///c:/dir/test.mht!x-usc:123abc"
1498 "mhtml:file:///c:/dir/test.mht!http://test.org", "",
1499 "mhtml:file:///c:/dir/test.mht"
1503 static void test_mhtml_protocol_info(void)
1505 WCHAR
*base_url
, *relative_url
, combined_url
[INTERNET_MAX_URL_LENGTH
];
1506 IInternetProtocolInfo
*protocol_info
;
1511 static const WCHAR http_url
[] = {'h','t','t','p',':','/','/','t','e','s','t','.','o','r','g',0};
1513 hres
= CoCreateInstance(&CLSID_IMimeHtmlProtocol
, NULL
, CLSCTX_INPROC_SERVER
,
1514 &IID_IInternetProtocolInfo
, (void**)&protocol_info
);
1515 ok(hres
== S_OK
, "Could not create protocol info: %08x\n", hres
);
1517 for(i
= 0; i
< sizeof(combine_tests
)/sizeof(*combine_tests
); i
++) {
1518 base_url
= a2w(combine_tests
[i
].base_url
);
1519 relative_url
= a2w(combine_tests
[i
].relative_url
);
1521 combined_len
= 0xdeadbeef;
1522 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, base_url
, relative_url
, ICU_BROWSER_MODE
,
1523 combined_url
, sizeof(combined_url
)/sizeof(WCHAR
), &combined_len
, 0);
1524 todo_wine_if(combine_tests
[i
].todo
)
1525 ok(hres
== S_OK
, "[%u] CombineUrl failed: %08x\n", i
, hres
);
1526 if(SUCCEEDED(hres
)) {
1527 exlen
= strlen(combine_tests
[i
].expected_result
);
1528 ok(combined_len
== exlen
, "[%u] combined len is %u, expected %u\n", i
, combined_len
, exlen
);
1529 ok(!strcmp_wa(combined_url
, combine_tests
[i
].expected_result
), "[%u] combined URL is %s, expected %s\n",
1530 i
, wine_dbgstr_w(combined_url
), combine_tests
[i
].expected_result
);
1532 combined_len
= 0xdeadbeef;
1533 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, base_url
, relative_url
, ICU_BROWSER_MODE
,
1534 combined_url
, exlen
, &combined_len
, 0);
1535 ok(hres
== E_FAIL
, "[%u] CombineUrl returned: %08x\n", i
, hres
);
1536 ok(!combined_len
, "[%u] combined_len = %u\n", i
, combined_len
);
1539 HeapFree(GetProcessHeap(), 0, base_url
);
1540 HeapFree(GetProcessHeap(), 0, relative_url
);
1543 hres
= IInternetProtocolInfo_CombineUrl(protocol_info
, http_url
, http_url
, ICU_BROWSER_MODE
,
1544 combined_url
, sizeof(combined_url
)/sizeof(WCHAR
), &combined_len
, 0);
1545 ok(hres
== E_FAIL
, "CombineUrl failed: %08x\n", hres
);
1547 IInternetProtocolInfo_Release(protocol_info
);
1550 static HRESULT WINAPI
outer_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
1552 ok(0, "unexpected call\n");
1553 return E_NOINTERFACE
;
1556 static ULONG WINAPI
outer_AddRef(IUnknown
*iface
)
1561 static ULONG WINAPI
outer_Release(IUnknown
*iface
)
1566 static const IUnknownVtbl outer_vtbl
= {
1567 outer_QueryInterface
,
1572 static BOOL broken_mhtml_resolver
;
1574 static void test_mhtml_protocol(void)
1576 IUnknown outer
= { &outer_vtbl
};
1577 IClassFactory
*class_factory
;
1578 IUnknown
*unk
, *unk2
;
1582 /* test class factory */
1583 hres
= CoGetClassObject(&CLSID_IMimeHtmlProtocol
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IUnknown
, (void**)&unk
);
1584 ok(hres
== S_OK
, "CoGetClassObject failed: %08x\n", hres
);
1586 hres
= IUnknown_QueryInterface(unk
, &IID_IInternetProtocolInfo
, (void**)&unk2
);
1587 ok(hres
== E_NOINTERFACE
, "IInternetProtocolInfo supported\n");
1589 hres
= IUnknown_QueryInterface(unk
, &IID_IClassFactory
, (void**)&class_factory
);
1590 ok(hres
== S_OK
, "Could not get IClassFactory iface: %08x\n", hres
);
1591 IUnknown_Release(unk
);
1593 hres
= IClassFactory_CreateInstance(class_factory
, &outer
, &IID_IUnknown
, (void**)&unk
);
1594 ok(hres
== S_OK
, "CreateInstance returned: %08x\n", hres
);
1595 hres
= IUnknown_QueryInterface(unk
, &IID_IInternetProtocol
, (void**)&unk2
);
1596 ok(hres
== S_OK
, "Could not get IInternetProtocol iface: %08x\n", hres
);
1597 IUnknown_Release(unk2
);
1598 IUnknown_Release(unk
);
1600 hres
= IClassFactory_CreateInstance(class_factory
, (IUnknown
*)0xdeadbeef, &IID_IInternetProtocol
, (void**)&unk2
);
1601 ok(hres
== CLASS_E_NOAGGREGATION
, "CreateInstance returned: %08x\n", hres
);
1603 IClassFactory_Release(class_factory
);
1605 if(!broken_mhtml_resolver
)
1606 test_mhtml_protocol_info();
1608 for(i
= 0; i
< sizeof(binding_tests
)/sizeof(*binding_tests
); i
++)
1609 test_mhtml_protocol_binding(binding_tests
+ i
);
1612 static void test_MimeOleObjectFromMoniker(void)
1614 IMoniker
*mon
, *new_mon
;
1615 WCHAR
*mhtml_url
, *url
;
1621 static const struct {
1623 const char *mhtml_url
;
1625 {"file:///x:\\dir\\file.mht", "mhtml:file://x:\\dir\\file.mht"},
1626 {"file:///x:/dir/file.mht", "mhtml:file://x:\\dir\\file.mht"},
1627 {"http://www.winehq.org/index.html?query#hash", "mhtml:http://www.winehq.org/index.html?query#hash"},
1628 {"../test.mht", "mhtml:../test.mht"}
1631 for(i
= 0; i
< sizeof(tests
)/sizeof(*tests
); i
++) {
1632 url
= a2w(tests
[i
].url
);
1633 hres
= CreateURLMoniker(NULL
, url
, &mon
);
1634 ok(hres
== S_OK
, "CreateURLMoniker failed: %08x\n", hres
);
1635 HeapFree(GetProcessHeap(), 0, url
);
1637 hres
= CreateBindCtx(0, &bind_ctx
);
1638 ok(hres
== S_OK
, "CreateBindCtx failed: %08x\n", hres
);
1640 hres
= MimeOleObjectFromMoniker(0, mon
, bind_ctx
, &IID_IUnknown
, (void**)&unk
, &new_mon
);
1641 ok(hres
== S_OK
|| broken(!i
&& hres
== INET_E_RESOURCE_NOT_FOUND
), "MimeOleObjectFromMoniker failed: %08x\n", hres
);
1642 IBindCtx_Release(bind_ctx
);
1643 if(hres
== INET_E_RESOURCE_NOT_FOUND
) { /* winxp */
1644 win_skip("Broken MHTML behaviour found. Skipping some tests.\n");
1645 broken_mhtml_resolver
= TRUE
;
1649 hres
= IMoniker_GetDisplayName(new_mon
, NULL
, NULL
, &mhtml_url
);
1650 ok(hres
== S_OK
, "GetDisplayName failed: %08x\n", hres
);
1651 ok(!strcmp_wa(mhtml_url
, tests
[i
].mhtml_url
), "[%d] unexpected mhtml URL: %s\n", i
, wine_dbgstr_w(mhtml_url
));
1652 CoTaskMemFree(mhtml_url
);
1654 IUnknown_Release(unk
);
1655 IMoniker_Release(new_mon
);
1656 IMoniker_Release(mon
);
1662 OleInitialize(NULL
);
1663 test_CreateVirtualStream();
1664 test_CreateSecurity();
1668 test_CreateMessage();
1669 test_MessageSetProp();
1670 test_MessageGetPropInfo();
1671 test_MessageOptions();
1672 test_BindToObject();
1673 test_BodyDeleteProp();
1674 test_MimeOleGetPropertySchema();
1675 test_mhtml_message();
1676 test_MimeOleObjectFromMoniker();
1677 test_mhtml_protocol();