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