urlmon/tests: Add tests for calls to IBindStatusCallback_QueryInterface.
[wine] / dlls / urlmon / tests / url.c
1 /*
2  * UrlMon URL tests
3  *
4  * Copyright 2004 Kevin Koltzau
5  * Copyright 2004 Jacek Caban
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #define COBJMACROS
25 #define CONST_VTABLE
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "urlmon.h"
30 #include "wininet.h"
31
32 #include "wine/test.h"
33
34 #define DEFINE_EXPECT(func) \
35     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
36
37 #define SET_EXPECT(func) \
38     expect_ ## func = TRUE
39
40 #define CHECK_EXPECT(func) \
41     do { \
42         ok(expect_ ##func, "unexpected call " #func "\n"); \
43         expect_ ## func = FALSE; \
44         called_ ## func = TRUE; \
45     }while(0)
46
47 #define CHECK_EXPECT2(func) \
48     do { \
49         ok(expect_ ##func, "unexpected call " #func "\n"); \
50         called_ ## func = TRUE; \
51     }while(0)
52
53 #define CHECK_CALLED(func) \
54     do { \
55         ok(called_ ## func, "expected " #func "\n"); \
56         expect_ ## func = called_ ## func = FALSE; \
57     }while(0)
58
59 #define CHECK_NOT_CALLED(func) \
60     do { \
61         ok(!called_ ## func, "unexpected " #func "\n"); \
62         expect_ ## func = called_ ## func = FALSE; \
63     }while(0)
64
65 #define CLEAR_CALLED(func) \
66     expect_ ## func = called_ ## func = FALSE
67
68 DEFINE_EXPECT(QueryInterface_IServiceProvider);
69 DEFINE_EXPECT(QueryInterface_IHttpNegotiate);
70 DEFINE_EXPECT(QueryInterface_IHttpNegotiate2);
71 DEFINE_EXPECT(GetBindInfo);
72 DEFINE_EXPECT(OnStartBinding);
73 DEFINE_EXPECT(OnProgress_FINDINGRESOURCE);
74 DEFINE_EXPECT(OnProgress_CONNECTING);
75 DEFINE_EXPECT(OnProgress_SENDINGREQUEST);
76 DEFINE_EXPECT(OnProgress_MIMETYPEAVAILABLE);
77 DEFINE_EXPECT(OnProgress_BEGINDOWNLOADDATA);
78 DEFINE_EXPECT(OnProgress_DOWNLOADINGDATA);
79 DEFINE_EXPECT(OnProgress_ENDDOWNLOADDATA);
80 DEFINE_EXPECT(OnStopBinding);
81 DEFINE_EXPECT(OnDataAvailable);
82 DEFINE_EXPECT(Start);
83 DEFINE_EXPECT(Read);
84 DEFINE_EXPECT(LockRequest);
85 DEFINE_EXPECT(Terminate);
86 DEFINE_EXPECT(UnlockRequest);
87
88 static const WCHAR TEST_URL_1[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','\0'};
89 static const WCHAR TEST_PART_URL_1[] = {'/','t','e','s','t','/','\0'};
90
91 static const WCHAR WINE_ABOUT_URL[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.',
92                                        'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0};
93 static const WCHAR ABOUT_BLANK[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
94 static WCHAR INDEX_HTML[MAX_PATH];
95 static const WCHAR ITS_URL[] =
96     {'i','t','s',':','t','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0};
97 static const WCHAR MK_URL[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':',
98     't','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0};
99
100
101
102 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
103
104 static BOOL stopped_binding = FALSE, emulate_protocol = FALSE;
105 static DWORD read = 0;
106
107 static const LPCWSTR urls[] = {
108     WINE_ABOUT_URL,
109     ABOUT_BLANK,
110     INDEX_HTML,
111     ITS_URL,
112     MK_URL
113 };
114
115 static enum {
116     HTTP_TEST,
117     ABOUT_TEST,
118     FILE_TEST,
119     ITS_TEST,
120     MK_TEST
121 } test_protocol;
122
123 static void test_CreateURLMoniker(LPCWSTR url1, LPCWSTR url2)
124 {
125     HRESULT hr;
126     IMoniker *mon1 = NULL;
127     IMoniker *mon2 = NULL;
128
129     hr = CreateURLMoniker(NULL, url1, &mon1);
130     ok(SUCCEEDED(hr), "failed to create moniker: 0x%08x\n", hr);
131     if(SUCCEEDED(hr)) {
132         hr = CreateURLMoniker(mon1, url2, &mon2);
133         ok(SUCCEEDED(hr), "failed to create moniker: 0x%08x\n", hr);
134     }
135     if(mon1) IMoniker_Release(mon1);
136     if(mon2) IMoniker_Release(mon2);
137 }
138
139 static void test_create(void)
140 {
141     test_CreateURLMoniker(TEST_URL_1, TEST_PART_URL_1);
142 }
143
144 static HRESULT WINAPI Protocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
145 {
146     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) {
147         *ppv = iface;
148         return S_OK;
149     }
150
151     *ppv = NULL;
152     return E_NOINTERFACE;
153 }
154
155 static ULONG WINAPI Protocol_AddRef(IInternetProtocol *iface)
156 {
157     return 2;
158 }
159
160 static ULONG WINAPI Protocol_Release(IInternetProtocol *iface)
161 {
162     return 1;
163 }
164
165 static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
166         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
167         DWORD grfPI, DWORD dwReserved)
168 {
169     BINDINFO bindinfo, bi = {sizeof(bi), 0};
170     DWORD bindf, bscf = BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
171     WCHAR null_char = 0;
172     HRESULT hres;
173
174     static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
175
176     CHECK_EXPECT(Start);
177
178     read = 0;
179
180     ok(szUrl && !lstrcmpW(szUrl, urls[test_protocol]), "wrong url\n");
181     ok(pOIProtSink != NULL, "pOIProtSink == NULL\n");
182     ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n");
183     ok(grfPI == 0, "grfPI=%d, expected 0\n", grfPI);
184     ok(dwReserved == 0, "dwReserved=%d, expected 0\n", dwReserved);
185
186     memset(&bindinfo, 0, sizeof(bindinfo));
187     bindinfo.cbSize = sizeof(bindinfo);
188     hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo);
189     ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres);
190
191     if(test_protocol == FILE_TEST || test_protocol == MK_TEST) {
192         ok(bindf == (BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE|BINDF_PULLDATA
193                      |BINDF_FROMURLMON),
194            "bindf=%08x\n", bindf);
195     }else {
196         ok(bindf == (BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE|BINDF_PULLDATA|
197                      BINDF_FROMURLMON|BINDF_NEEDFILE),
198            "bindf=%08x\n", bindf);
199     }
200
201     ok(!memcmp(&bindinfo, &bi, sizeof(bindinfo)), "wrong bindinfo\n");
202
203     switch(test_protocol) {
204     case MK_TEST:
205         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
206                 BINDSTATUS_DIRECTBIND, NULL);
207         ok(hres == S_OK,
208            "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres);
209
210     case FILE_TEST:
211     case ITS_TEST:
212         SET_EXPECT(OnProgress_SENDINGREQUEST);
213         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
214                 BINDSTATUS_SENDINGREQUEST, &null_char);
215         ok(hres == S_OK,
216            "ReportProgress(BINDSTATUS_SENDINGREQUEST) failed: %08x\n", hres);
217         CHECK_CALLED(OnProgress_SENDINGREQUEST);
218     default:
219         break;
220     }
221
222     if(test_protocol == FILE_TEST) {
223         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
224                 BINDSTATUS_CACHEFILENAMEAVAILABLE, &null_char);
225         ok(hres == S_OK,
226            "ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE) failed: %08x\n", hres);
227
228         SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
229         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
230                 BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, wszTextHtml);
231         ok(hres == S_OK,
232            "ReportProgress(BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE) failed: %08x\n", hres);
233         CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
234     }else {
235         hres = IInternetProtocolSink_ReportProgress(pOIProtSink,
236                 BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml);
237         ok(hres == S_OK,
238            "ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE) failed: %08x\n", hres);
239     }
240
241     if(test_protocol == ABOUT_TEST)
242         bscf |= BSCF_DATAFULLYAVAILABLE;
243     if(test_protocol == ITS_TEST)
244         bscf = BSCF_FIRSTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
245
246     SET_EXPECT(Read);
247     if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
248         SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
249     SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
250     SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
251     SET_EXPECT(LockRequest);
252     SET_EXPECT(OnDataAvailable);
253     SET_EXPECT(OnStopBinding);
254
255     hres = IInternetProtocolSink_ReportData(pOIProtSink, bscf, 13, 13);
256     ok(hres == S_OK, "ReportData failed: %08x\n", hres);
257
258     CHECK_CALLED(Read);
259     if(test_protocol != FILE_TEST && test_protocol != MK_TEST)
260         CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
261     CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
262     CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
263     CHECK_CALLED(LockRequest);
264     CHECK_CALLED(OnDataAvailable);
265     CHECK_CALLED(OnStopBinding);
266
267     if(test_protocol == ITS_TEST) {
268         SET_EXPECT(Read);
269         hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_BEGINDOWNLOADDATA, NULL);
270         ok(hres == S_OK, "ReportProgress(BINDSTATUS_BEGINDOWNLOADDATA) failed: %08x\n", hres);
271         CHECK_CALLED(Read);
272     }
273
274     SET_EXPECT(Terminate);
275     hres = IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
276     ok(hres == S_OK, "ReportResult failed: %08x\n", hres);
277     CHECK_CALLED(Terminate);
278
279     return S_OK;
280 }
281
282 static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface,
283         PROTOCOLDATA *pProtocolData)
284 {
285     ok(0, "unexpected call\n");
286     return E_NOTIMPL;
287 }
288
289 static HRESULT WINAPI Protocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
290         DWORD dwOptions)
291 {
292     ok(0, "unexpected call\n");
293     return E_NOTIMPL;
294 }
295
296 static HRESULT WINAPI Protocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
297 {
298     CHECK_EXPECT(Terminate);
299     ok(dwOptions == 0, "dwOptions=%d, expected 0\n", dwOptions);
300     return S_OK;
301 }
302
303 static HRESULT WINAPI Protocol_Suspend(IInternetProtocol *iface)
304 {
305     ok(0, "unexpected call\n");
306     return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI Protocol_Resume(IInternetProtocol *iface)
310 {
311     ok(0, "unexpected call\n");
312     return E_NOTIMPL;
313 }
314
315 static HRESULT WINAPI Protocol_Read(IInternetProtocol *iface, void *pv,
316         ULONG cb, ULONG *pcbRead)
317 {
318     static const char data[] = "<HTML></HTML>";
319
320     CHECK_EXPECT2(Read);
321
322     if(read) {
323         *pcbRead = 0;
324         return S_FALSE;
325     }
326
327     ok(pv != NULL, "pv == NULL\n");
328     ok(cb != 0, "cb == 0\n");
329     ok(pcbRead != NULL, "pcbRead == NULL\n");
330     if(pcbRead) {
331         ok(*pcbRead == 0, "*pcbRead=%d, expected 0\n", *pcbRead);
332         read += *pcbRead = sizeof(data)-1;
333     }
334     if(pv)
335         memcpy(pv, data, sizeof(data));
336
337     return S_OK;
338 }
339
340 static HRESULT WINAPI Protocol_Seek(IInternetProtocol *iface,
341         LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
342 {
343     ok(0, "unexpected call\n");
344     return E_NOTIMPL;
345 }
346
347 static HRESULT WINAPI Protocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
348 {
349     CHECK_EXPECT(LockRequest);
350     return S_OK;
351 }
352
353 static HRESULT WINAPI Protocol_UnlockRequest(IInternetProtocol *iface)
354 {
355     CHECK_EXPECT(UnlockRequest);
356     return S_OK;
357 }
358
359 static const IInternetProtocolVtbl ProtocolVtbl = {
360     Protocol_QueryInterface,
361     Protocol_AddRef,
362     Protocol_Release,
363     Protocol_Start,
364     Protocol_Continue,
365     Protocol_Abort,
366     Protocol_Terminate,
367     Protocol_Suspend,
368     Protocol_Resume,
369     Protocol_Read,
370     Protocol_Seek,
371     Protocol_LockRequest,
372     Protocol_UnlockRequest
373 };
374
375 static IInternetProtocol Protocol = { &ProtocolVtbl };
376
377 static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
378 {
379     if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
380         if(emulate_protocol) {
381             *ppv = &Protocol;
382             return S_OK;
383         }else {
384             return E_NOINTERFACE;
385         }
386     }
387     else if (IsEqualGUID(&IID_IServiceProvider, riid))
388     {
389         CHECK_EXPECT(QueryInterface_IServiceProvider);
390     }
391     else if (IsEqualGUID(&IID_IHttpNegotiate, riid))
392     {
393         CHECK_EXPECT(QueryInterface_IHttpNegotiate);
394     }
395     else if (IsEqualGUID(&IID_IHttpNegotiate2, riid))
396     {
397         CHECK_EXPECT(QueryInterface_IHttpNegotiate2);
398     }
399
400     return E_NOINTERFACE;
401 }
402
403 static ULONG WINAPI statusclb_AddRef(IBindStatusCallback *iface)
404 {
405     return 2;
406 }
407
408 static ULONG WINAPI statusclb_Release(IBindStatusCallback *iface)
409 {
410     return 1;
411 }
412
413 static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
414         IBinding *pib)
415 {
416     HRESULT hres;
417     IMoniker *mon;
418
419     CHECK_EXPECT(OnStartBinding);
420
421     ok(pib != NULL, "pib should not be NULL\n");
422
423     hres = IBinding_QueryInterface(pib, &IID_IMoniker, (void**)&mon);
424     ok(hres == E_NOINTERFACE, "IBinding should not have IMoniker interface\n");
425     if(SUCCEEDED(hres))
426         IMoniker_Release(mon);
427
428     return S_OK;
429 }
430
431 static HRESULT WINAPI statusclb_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
432 {
433     ok(0, "unexpected call\n");
434     return E_NOTIMPL;
435 }
436
437 static HRESULT WINAPI statusclb_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
438 {
439     ok(0, "unexpected call\n");
440     return E_NOTIMPL;
441 }
442
443 static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
444         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
445 {
446     switch(ulStatusCode) {
447     case BINDSTATUS_FINDINGRESOURCE:
448         CHECK_EXPECT(OnProgress_FINDINGRESOURCE);
449         break;
450     case BINDSTATUS_CONNECTING:
451         CHECK_EXPECT(OnProgress_CONNECTING);
452         break;
453     case BINDSTATUS_SENDINGREQUEST:
454         CHECK_EXPECT(OnProgress_SENDINGREQUEST);
455         break;
456     case BINDSTATUS_MIMETYPEAVAILABLE:
457         CHECK_EXPECT(OnProgress_MIMETYPEAVAILABLE);
458         break;
459     case BINDSTATUS_BEGINDOWNLOADDATA:
460         CHECK_EXPECT(OnProgress_BEGINDOWNLOADDATA);
461         ok(szStatusText != NULL, "szStatusText == NULL\n");
462         if(szStatusText)
463             ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n");
464         break;
465     case BINDSTATUS_DOWNLOADINGDATA:
466         CHECK_EXPECT2(OnProgress_DOWNLOADINGDATA);
467         break;
468     case BINDSTATUS_ENDDOWNLOADDATA:
469         CHECK_EXPECT(OnProgress_ENDDOWNLOADDATA);
470         ok(szStatusText != NULL, "szStatusText == NULL\n");
471         if(szStatusText)
472             ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n");
473         break;
474     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
475         ok(szStatusText != NULL, "szStatusText == NULL\n");
476         if(szStatusText && test_protocol == FILE_TEST)
477             ok(!lstrcmpW(INDEX_HTML+7, szStatusText), "wrong szStatusText\n");
478         break;
479     default:
480         todo_wine { ok(0, "unexpexted code %d\n", ulStatusCode); }
481     };
482     return S_OK;
483 }
484
485 static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
486 {
487     CHECK_EXPECT(OnStopBinding);
488
489     /* ignore DNS failure */
490     if (hresult != HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED))
491     {
492         ok(SUCCEEDED(hresult), "Download failed: %08x\n", hresult);
493         ok(szError == NULL, "szError should be NULL\n");
494     }
495     stopped_binding = TRUE;
496
497     return S_OK;
498 }
499
500 static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
501 {
502     DWORD cbSize;
503
504     CHECK_EXPECT(GetBindInfo);
505
506     *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
507     cbSize = pbindinfo->cbSize;
508     memset(pbindinfo, 0, cbSize);
509     pbindinfo->cbSize = cbSize;
510
511     return S_OK;
512 }
513
514 static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
515         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
516 {
517     HRESULT hres;
518     DWORD readed;
519     BYTE buf[512];
520
521     CHECK_EXPECT2(OnDataAvailable);
522
523     if (0)
524     {
525     /* FIXME: Uncomment after removing BindToStorage hack. */
526     ok(pformatetc != NULL, "pformatetx == NULL\n");
527     if(pformatetc) {
528         ok(pformatetc->cfFormat == 0xc02d, "clipformat=%x\n", pformatetc->cfFormat); 
529         ok(pformatetc->ptd == NULL, "ptd = %p\n", pformatetc->ptd);
530         ok(pformatetc->dwAspect == 1, "dwAspect=%u\n", pformatetc->dwAspect);
531         ok(pformatetc->lindex == -1, "lindex=%d\n", pformatetc->lindex);
532         ok(pformatetc->tymed == TYMED_ISTREAM, "tymed=%u\n", pformatetc->tymed);
533     }
534
535     ok(pstgmed != NULL, "stgmeg == NULL\n");
536     if(pstgmed) {
537         ok(pstgmed->tymed == TYMED_ISTREAM, "tymed=%u\n", pstgmed->tymed);
538         ok(U(*pstgmed).pstm != NULL, "pstm == NULL\n");
539         ok(pstgmed->pUnkForRelease != NULL, "pUnkForRelease == NULL\n");
540     }
541     }
542
543     if(U(*pstgmed).pstm) {
544         do hres = IStream_Read(U(*pstgmed).pstm, buf, 512, &readed);
545         while(hres == S_OK);
546         ok(hres == S_FALSE || hres == E_PENDING, "IStream_Read returned %08x\n", hres);
547     }
548
549     return S_OK;
550 }
551
552 static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
553 {
554     ok(0, "unexpected call\n");
555     return E_NOTIMPL;
556 }
557
558 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
559     statusclb_QueryInterface,
560     statusclb_AddRef,
561     statusclb_Release,
562     statusclb_OnStartBinding,
563     statusclb_GetPriority,
564     statusclb_OnLowResource,
565     statusclb_OnProgress,
566     statusclb_OnStopBinding,
567     statusclb_GetBindInfo,
568     statusclb_OnDataAvailable,
569     statusclb_OnObjectAvailable
570 };
571
572 static IBindStatusCallback bsc = { &BindStatusCallbackVtbl };
573
574 static void test_CreateAsyncBindCtx(void)
575 {
576     IBindCtx *bctx = (IBindCtx*)0x0ff00ff0;
577     HRESULT hres;
578     ULONG ref;
579     BIND_OPTS bindopts;
580
581     hres = CreateAsyncBindCtx(0, NULL, NULL, &bctx);
582     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed. expected: E_INVALIDARG, got: %08x\n", hres);
583     ok(bctx == (IBindCtx*)0x0ff00ff0, "bctx should not be changed\n");
584
585     hres = CreateAsyncBindCtx(0, NULL, NULL, NULL);
586     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed. expected: E_INVALIDARG, got: %08x\n", hres);
587
588     SET_EXPECT(QueryInterface_IServiceProvider);
589     hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx);
590     ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08x\n", hres);
591     todo_wine CHECK_CALLED(QueryInterface_IServiceProvider);
592
593     bindopts.cbStruct = sizeof(bindopts);
594     hres = IBindCtx_GetBindOptions(bctx, &bindopts);
595     ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08x\n", hres);
596     ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
597                 "bindopts.grfFlags = %08x, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
598     ok(bindopts.grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE),
599                 "bindopts.grfMode = %08x, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n",
600                 bindopts.grfMode);
601     ok(bindopts.dwTickCountDeadline == 0,
602                 "bindopts.dwTickCountDeadline = %08x, expected: 0\n", bindopts.dwTickCountDeadline);
603
604     ref = IBindCtx_Release(bctx);
605     ok(ref == 0, "bctx should be destroyed here\n");
606 }
607
608 static void test_CreateAsyncBindCtxEx(void)
609 {
610     IBindCtx *bctx = NULL, *bctx_arg = NULL;
611     BIND_OPTS bindopts;
612     HRESULT hres;
613
614     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, NULL, 0);
615     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed: %08x, expected E_INVALIDARG\n", hres);
616
617     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &bctx, 0);
618     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres);
619
620     if(SUCCEEDED(hres)) {
621         bindopts.cbStruct = sizeof(bindopts);
622         hres = IBindCtx_GetBindOptions(bctx, &bindopts);
623         ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08x\n", hres);
624         ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
625                 "bindopts.grfFlags = %08x, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
626         ok(bindopts.grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE),
627                 "bindopts.grfMode = %08x, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n",
628                 bindopts.grfMode);
629         ok(bindopts.dwTickCountDeadline == 0,
630                 "bindopts.dwTickCountDeadline = %08x, expected: 0\n", bindopts.dwTickCountDeadline);
631
632         IBindCtx_Release(bctx);
633     }
634
635     CreateBindCtx(0, &bctx_arg);
636     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &bctx, 0);
637     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres);
638
639     if(SUCCEEDED(hres)) {
640         bindopts.cbStruct = sizeof(bindopts);
641         hres = IBindCtx_GetBindOptions(bctx, &bindopts);
642         ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08x\n", hres);
643         ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
644                 "bindopts.grfFlags = %08x, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
645         ok(bindopts.grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE),
646                 "bindopts.grfMode = %08x, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n",
647                 bindopts.grfMode);
648         ok(bindopts.dwTickCountDeadline == 0,
649                 "bindopts.dwTickCountDeadline = %08x, expected: 0\n", bindopts.dwTickCountDeadline);
650
651         IBindCtx_Release(bctx);
652     }
653
654     IBindCtx_Release(bctx_arg);
655
656     SET_EXPECT(QueryInterface_IServiceProvider);
657     hres = CreateAsyncBindCtxEx(NULL, 0, &bsc, NULL, &bctx, 0);
658     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres);
659     todo_wine CHECK_CALLED(QueryInterface_IServiceProvider);
660
661     if(SUCCEEDED(hres))
662         IBindCtx_Release(bctx);
663 }
664
665 static void test_BindToStorage(int protocol, BOOL emul)
666 {
667     IMoniker *mon;
668     HRESULT hres;
669     LPOLESTR display_name;
670     IBindCtx *bctx;
671     MSG msg;
672     IBindStatusCallback *previousclb;
673     IUnknown *unk = (IUnknown*)0x00ff00ff;
674     IBinding *bind;
675
676     test_protocol = protocol;
677     emulate_protocol = emul;
678
679     SET_EXPECT(QueryInterface_IServiceProvider);
680     hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx);
681     ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08x\n\n", hres);
682     if(FAILED(hres))
683         return;
684     if(test_protocol == HTTP_TEST ||
685        test_protocol == ABOUT_TEST ||
686        (emul && test_protocol == FILE_TEST)) todo_wine
687         CHECK_CALLED(QueryInterface_IServiceProvider);
688     else
689         CHECK_CALLED(QueryInterface_IServiceProvider);
690
691     SET_EXPECT(QueryInterface_IServiceProvider);
692     hres = RegisterBindStatusCallback(bctx, &bsc, &previousclb, 0);
693     ok(SUCCEEDED(hres), "RegisterBindStatusCallback failed: %08x\n", hres);
694     ok(previousclb == &bsc, "previousclb(%p) != sclb(%p)\n", previousclb, &bsc);
695     todo_wine CHECK_CALLED(QueryInterface_IServiceProvider);
696     if(previousclb)
697         IBindStatusCallback_Release(previousclb);
698
699     hres = CreateURLMoniker(NULL, urls[test_protocol], &mon);
700     ok(SUCCEEDED(hres), "failed to create moniker: %08x\n", hres);
701     if(FAILED(hres)) {
702         IBindCtx_Release(bctx);
703         return;
704     }
705
706     if(test_protocol == FILE_TEST && INDEX_HTML[7] == '/')
707         memmove(INDEX_HTML+7, INDEX_HTML+8, lstrlenW(INDEX_HTML+7)*sizeof(WCHAR));
708
709     hres = IMoniker_QueryInterface(mon, &IID_IBinding, (void**)&bind);
710     ok(hres == E_NOINTERFACE, "IMoniker should not have IBinding interface\n");
711     if(SUCCEEDED(hres))
712         IBinding_Release(bind);
713
714     hres = IMoniker_GetDisplayName(mon, bctx, NULL, &display_name);
715     ok(hres == S_OK, "GetDisplayName failed %08x\n", hres);
716     ok(!lstrcmpW(display_name, urls[test_protocol]), "GetDisplayName got wrong name\n");
717
718     SET_EXPECT(QueryInterface_IServiceProvider);
719     SET_EXPECT(GetBindInfo);
720     SET_EXPECT(OnStartBinding);
721     if(emulate_protocol) {
722         SET_EXPECT(Start);
723         SET_EXPECT(UnlockRequest);
724     }else {
725         if(test_protocol == HTTP_TEST) {
726             SET_EXPECT(QueryInterface_IHttpNegotiate);
727             SET_EXPECT(QueryInterface_IHttpNegotiate2);
728             SET_EXPECT(OnProgress_FINDINGRESOURCE);
729             SET_EXPECT(OnProgress_CONNECTING);
730         }
731         if(test_protocol == HTTP_TEST || test_protocol == FILE_TEST)
732             SET_EXPECT(OnProgress_SENDINGREQUEST);
733         SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
734         SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
735         if(test_protocol == HTTP_TEST)
736             SET_EXPECT(OnProgress_DOWNLOADINGDATA);
737         SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
738         SET_EXPECT(OnDataAvailable);
739         SET_EXPECT(OnStopBinding);
740     }
741
742     hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk);
743     if (test_protocol == HTTP_TEST && hres == HRESULT_FROM_WIN32(ERROR_INTERNET_NAME_NOT_RESOLVED))
744     {
745         trace( "Network unreachable, skipping tests\n" );
746         return;
747     }
748     ok(SUCCEEDED(hres), "IMoniker_BindToStorage failed: %08x\n", hres);
749     if (!SUCCEEDED(hres)) return;
750
751     if(test_protocol == HTTP_TEST) {
752         todo_wine {
753             ok(unk == NULL, "istr should be NULL\n");
754         }
755     }else {
756         ok(unk != NULL, "unk == NULL\n");
757     }
758     if(unk)
759         IUnknown_Release(unk);
760
761     while(!stopped_binding && GetMessage(&msg,NULL,0,0)) {
762         TranslateMessage(&msg);
763         DispatchMessage(&msg);
764     }
765
766     CHECK_CALLED(GetBindInfo);
767     CHECK_CALLED(OnStartBinding);
768     if(emulate_protocol) {
769         CHECK_CALLED(Start);
770         CHECK_CALLED(UnlockRequest);
771     }else {
772         if(test_protocol == HTTP_TEST) {
773             todo_wine CHECK_CALLED(QueryInterface_IHttpNegotiate);
774             /* QueryInterface_IHttpNegotiate2 called on WinXP but not on Win98 */
775             CLEAR_CALLED(QueryInterface_IHttpNegotiate2);
776             CHECK_CALLED(OnProgress_FINDINGRESOURCE);
777             CHECK_CALLED(OnProgress_CONNECTING);
778             CHECK_CALLED(OnProgress_SENDINGREQUEST);
779             todo_wine { CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); }
780         }else {
781             todo_wine CHECK_NOT_CALLED(QueryInterface_IServiceProvider);
782             CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
783         }
784         CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
785         if(test_protocol == HTTP_TEST)
786             CHECK_CALLED(OnProgress_DOWNLOADINGDATA);
787         CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
788         CHECK_CALLED(OnDataAvailable);
789         CHECK_CALLED(OnStopBinding);
790     }
791
792     ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
793     ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
794 }
795
796 static void set_file_url(void)
797 {
798     int len;
799
800     static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'};
801
802     memcpy(INDEX_HTML, wszFile, sizeof(wszFile));
803     len = sizeof(wszFile)/sizeof(WCHAR);
804     INDEX_HTML[len++] = '/';
805     len += GetCurrentDirectoryW(sizeof(INDEX_HTML)/sizeof(WCHAR)-len, INDEX_HTML+len);
806     INDEX_HTML[len++] = '\\';
807     memcpy(INDEX_HTML+len, wszIndexHtml, sizeof(wszIndexHtml));
808 }
809
810 static void create_file(void)
811 {
812     HANDLE file;
813     DWORD size;
814
815     static const char html_doc[] = "<HTML></HTML>";
816
817     file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
818             FILE_ATTRIBUTE_NORMAL, NULL);
819     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n");
820     if(file == INVALID_HANDLE_VALUE)
821         return;
822
823     WriteFile(file, html_doc, sizeof(html_doc)-1, &size, NULL);
824     CloseHandle(file);
825
826     set_file_url();
827 }
828
829 static void test_BindToStorage_fail(void)
830 {
831     IMoniker *mon = NULL;
832     IBindCtx *bctx = NULL;
833     IUnknown *unk;
834     HRESULT hres;
835
836     hres = CreateURLMoniker(NULL, ABOUT_BLANK, &mon);
837     ok(hres == S_OK, "CreateURLMoniker failed: %08x\n", hres);
838     if(FAILED(hres))
839         return;
840
841     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &bctx, 0);
842     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08x\n", hres);
843
844     hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk);
845     ok(hres == MK_E_SYNTAX, "hres=%08x, expected INET_E_SYNTAX\n", hres);
846
847     IBindCtx_Release(bctx);
848
849     IMoniker_Release(mon);
850 }
851
852 START_TEST(url)
853 {
854     test_create();
855     test_CreateAsyncBindCtx();
856     test_CreateAsyncBindCtxEx();
857
858     trace("http test...\n");
859     test_BindToStorage(HTTP_TEST, FALSE);
860
861     trace("about test...\n");
862     CoInitialize(NULL);
863     test_BindToStorage(ABOUT_TEST, FALSE);
864     CoUninitialize();
865
866     trace("emulated about test...\n");
867     test_BindToStorage(ABOUT_TEST, TRUE);
868
869     trace("file test...\n");
870     create_file();
871     test_BindToStorage(FILE_TEST, FALSE);
872     DeleteFileW(wszIndexHtml);
873
874     trace("emulated file test...\n");
875     set_file_url();
876     test_BindToStorage(FILE_TEST, TRUE);
877
878     trace("emulated its test...\n");
879     test_BindToStorage(ITS_TEST, TRUE);
880
881     trace("emulated mk test...\n");
882     test_BindToStorage(MK_TEST, TRUE);
883
884     test_BindToStorage_fail();
885 }