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