Added CreateAsyncBindCtxEx 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 static const WCHAR TEST_URL_1[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','\0'};
33 static const WCHAR TEST_PART_URL_1[] = {'/','t','e','s','t','/','\0'};
34
35 static const WCHAR WINE_ABOUT_URL[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.',
36                                        'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0};
37 static BOOL stopped_binding = FALSE;
38
39 static void test_CreateURLMoniker(LPCWSTR url1, LPCWSTR url2)
40 {
41     HRESULT hr;
42     IMoniker *mon1 = NULL;
43     IMoniker *mon2 = NULL;
44
45     hr = CreateURLMoniker(NULL, url1, &mon1);
46     ok(SUCCEEDED(hr), "failed to create moniker: 0x%08lx\n", hr);
47     if(SUCCEEDED(hr)) {
48         hr = CreateURLMoniker(mon1, url2, &mon2);
49         ok(SUCCEEDED(hr), "failed to create moniker: 0x%08lx\n", hr);
50     }
51     if(mon1) IMoniker_Release(mon1);
52     if(mon2) IMoniker_Release(mon2);
53 }
54
55 static void test_create(void)
56 {
57     test_CreateURLMoniker(TEST_URL_1, TEST_PART_URL_1);
58 }
59
60 typedef struct {
61     const IBindStatusCallbackVtbl *lpVtbl;
62     LONG ref;
63     IBinding *pbind;
64     IStream *pstr;
65 } statusclb;
66
67 static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppvObject)
68 {
69     return E_NOINTERFACE;
70 }
71
72 static ULONG WINAPI statusclb_AddRef(IBindStatusCallback *iface)
73 {
74     return InterlockedIncrement(&((statusclb*)iface)->ref);
75 }
76
77 static ULONG WINAPI statusclb_Release(IBindStatusCallback *iface)
78 {
79     statusclb *This = (statusclb*)iface;
80     ULONG ref;
81     ref = InterlockedDecrement(&This->ref);
82     if(!ref)
83         HeapFree(GetProcessHeap(), 0, This);
84     return ref;
85 }
86
87 static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved, IBinding *pib)
88 {
89     statusclb *This = (statusclb*)iface;
90     HRESULT hres;
91     IMoniker *mon;
92
93     This->pbind = pib;
94     ok(pib != NULL, "pib should not be NULL\n");
95     if(pib)
96         IBinding_AddRef(pib);
97
98     hres = IBinding_QueryInterface(pib, &IID_IMoniker, (void**)&mon);
99     ok(hres == E_NOINTERFACE, "IBinding should not have IMoniker interface\n");
100     if(SUCCEEDED(hres))
101         IMoniker_Release(mon);
102
103     return S_OK;
104 }
105
106 static HRESULT WINAPI statusclb_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
107 {
108     return E_NOTIMPL;
109 }
110
111 static HRESULT WINAPI statusclb_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
112 {
113     return E_NOTIMPL;
114 }
115
116 static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulProgress, ULONG ulProgressMax,
117                            ULONG ulStatusCode, LPCWSTR szStatusText)
118 {
119     return S_OK;
120 }
121
122 static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
123 {
124     statusclb *This = (statusclb*)iface;
125
126     ok(SUCCEEDED(hresult), "Download failed: %08lx\n", hresult);
127     ok(szError == NULL, "szError should be NULL\n");
128     stopped_binding = TRUE;
129     IBinding_Release(This->pbind);
130     ok(This->pstr != NULL, "pstr should not be NULL here\n");
131     if(This->pstr)
132         IStream_Release(This->pstr);
133
134     return S_OK;
135 }
136
137 static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
138 {
139     DWORD cbSize;
140
141     *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
142     cbSize = pbindinfo->cbSize;
143     memset(pbindinfo, 0, cbSize);
144     pbindinfo->cbSize = cbSize;
145
146     return S_OK;
147 }
148
149 static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF, DWORD dwSize,
150                                                 FORMATETC* pformatetc, STGMEDIUM* pstgmed)
151 {
152     statusclb *This = (statusclb*)iface;
153     HRESULT hres;
154     DWORD readed;
155     BYTE buf[512];
156     if(!This->pstr) {
157         ok(grfBSCF & BSCF_FIRSTDATANOTIFICATION, "pstr should be set when BSCF_FIRSTDATANOTIFICATION\n");
158         This->pstr = U(*pstgmed).pstm;
159         IStream_AddRef(This->pstr);
160         ok(This->pstr != NULL, "pstr should not be NULL here\n");
161     }
162
163     do hres = IStream_Read(This->pstr, buf, 512, &readed);
164     while(hres == S_OK);
165     ok(hres == S_FALSE || hres == E_PENDING, "IStream_Read returned %08lx\n", hres);
166
167     return S_OK;
168 }
169
170 static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
171 {
172     return E_NOTIMPL;
173 }
174
175 static const IBindStatusCallbackVtbl statusclbVtbl = {
176     statusclb_QueryInterface,
177     statusclb_AddRef,
178     statusclb_Release,
179     statusclb_OnStartBinding,
180     statusclb_GetPriority,
181     statusclb_OnLowResource,
182     statusclb_OnProgress,
183     statusclb_OnStopBinding,
184     statusclb_GetBindInfo,
185     statusclb_OnDataAvailable,
186     statusclb_OnObjectAvailable
187 };
188
189 static IBindStatusCallback* statusclb_create(void)
190 {
191     statusclb *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(statusclb));
192     ret->lpVtbl = &statusclbVtbl;
193     ret->ref = 1;
194     ret->pbind = NULL;
195     ret->pstr = NULL;
196     return (IBindStatusCallback*)ret;
197 }
198
199 static void test_CreateAsyncBindCtx(void)
200 {
201     IBindCtx *bctx = (IBindCtx*)0x0ff00ff0;
202     HRESULT hres;
203     ULONG ref;
204     BIND_OPTS bindopts;
205     IBindStatusCallback *bsc = statusclb_create();
206
207     hres = CreateAsyncBindCtx(0, NULL, NULL, &bctx);
208     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed. expected: E_INVALIDARG, got: %08lx\n", hres);
209     ok(bctx == (IBindCtx*)0x0ff00ff0, "bctx should not be changed\n");
210
211     hres = CreateAsyncBindCtx(0, NULL, NULL, NULL);
212     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed. expected: E_INVALIDARG, got: %08lx\n", hres);
213
214     hres = CreateAsyncBindCtx(0, bsc, NULL, &bctx);
215     ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08lx\n", hres);
216     if(FAILED(hres)) {
217         IBindStatusCallback_Release(bsc);
218         return;
219     }
220
221     bindopts.cbStruct = sizeof(bindopts);
222     hres = IBindCtx_GetBindOptions(bctx, &bindopts);
223     ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08lx\n", hres);
224     ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
225                 "bindopts.grfFlags = %08lx, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
226     ok(bindopts.grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE),
227                 "bindopts.grfMode = %08lx, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n",
228                 bindopts.grfMode);
229     ok(bindopts.dwTickCountDeadline == 0,
230                 "bindopts.dwTickCountDeadline = %08lx, expected: 0\n", bindopts.dwTickCountDeadline);
231
232     ref = IBindCtx_Release(bctx);
233     ok(ref == 0, "bctx should be destroyed here\n");
234     ref = IBindStatusCallback_Release(bsc);
235     ok(ref == 0, "bsc should be destroyed here\n");
236 }
237
238 static void test_CreateAsyncBindCtxEx(void)
239 {
240     IBindCtx *bctx = NULL, *bctx_arg = NULL;
241     IBindStatusCallback *bsc = statusclb_create();
242     BIND_OPTS bindopts;
243     HRESULT hres;
244
245     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, NULL, 0);
246     ok(hres == E_INVALIDARG, "CreateAsyncBindCtx failed: %08lx, expected E_INVALIDARG\n", hres);
247
248     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &bctx, 0);
249     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08lx\n", hres);
250
251     if(SUCCEEDED(hres)) {
252         bindopts.cbStruct = sizeof(bindopts);
253         hres = IBindCtx_GetBindOptions(bctx, &bindopts);
254         ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08lx\n", hres);
255         ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
256                 "bindopts.grfFlags = %08lx, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
257         ok(bindopts.grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE),
258                 "bindopts.grfMode = %08lx, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n",
259                 bindopts.grfMode);
260         ok(bindopts.dwTickCountDeadline == 0,
261                 "bindopts.dwTickCountDeadline = %08lx, expected: 0\n", bindopts.dwTickCountDeadline);
262
263         IBindCtx_Release(bctx);
264     }
265
266     CreateBindCtx(0, &bctx_arg);
267     hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &bctx, 0);
268     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08lx\n", hres);
269
270     if(SUCCEEDED(hres)) {
271         bindopts.cbStruct = sizeof(bindopts);
272         hres = IBindCtx_GetBindOptions(bctx, &bindopts);
273         ok(SUCCEEDED(hres), "IBindCtx_GetBindOptions failed: %08lx\n", hres);
274         ok(bindopts.grfFlags == BIND_MAYBOTHERUSER,
275                 "bindopts.grfFlags = %08lx, expected: BIND_MAYBOTHERUSER\n", bindopts.grfFlags);
276         ok(bindopts.grfMode == (STGM_READWRITE | STGM_SHARE_EXCLUSIVE),
277                 "bindopts.grfMode = %08lx, expected: STGM_READWRITE | STGM_SHARE_EXCLUSIVE\n",
278                 bindopts.grfMode);
279         ok(bindopts.dwTickCountDeadline == 0,
280                 "bindopts.dwTickCountDeadline = %08lx, expected: 0\n", bindopts.dwTickCountDeadline);
281
282         IBindCtx_Release(bctx);
283     }
284
285     IBindCtx_Release(bctx_arg);
286
287     hres = CreateAsyncBindCtxEx(NULL, 0, bsc, NULL, &bctx, 0);
288     ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08lx\n", hres);
289
290     if(SUCCEEDED(hres))
291         IBindCtx_Release(bctx);
292
293     IBindStatusCallback_Release(bsc);
294 }
295
296 static void test_BindToStorage(void)
297 {
298     IMoniker *mon;
299     HRESULT hres;
300     LPOLESTR display_name;
301     IBindCtx *bctx;
302     MSG msg;
303     IBindStatusCallback *previousclb, *sclb = statusclb_create();
304     IUnknown *unk = (IUnknown*)0x00ff00ff;
305     IBinding *bind;
306
307     hres = CreateAsyncBindCtx(0, sclb, NULL, &bctx);
308     ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08lx\n\n", hres);
309     if(FAILED(hres)) {
310         IBindStatusCallback_Release(sclb);
311         return;
312     }
313
314     hres = RegisterBindStatusCallback(bctx, sclb, &previousclb, 0);
315     ok(SUCCEEDED(hres), "RegisterBindStatusCallback failed: %08lx\n", hres);
316     ok(previousclb == sclb, "previousclb(%p) != sclb(%p)\n", previousclb, sclb);
317     if(previousclb)
318         IBindStatusCallback_Release(previousclb);
319
320     hres = CreateURLMoniker(NULL, WINE_ABOUT_URL, &mon);
321     ok(SUCCEEDED(hres), "failed to create moniker: %08lx\n", hres);
322     if(FAILED(hres)) {
323         IBindStatusCallback_Release(sclb);
324         IBindCtx_Release(bctx);
325         return;
326     }
327
328     hres = IMoniker_QueryInterface(mon, &IID_IBinding, (void**)&bind);
329     ok(hres == E_NOINTERFACE, "IMoniker should not have IBinding interface\n");
330     if(SUCCEEDED(hres))
331         IBinding_Release(bind);
332
333     hres = IMoniker_GetDisplayName(mon, bctx, NULL, &display_name);
334     ok(SUCCEEDED(hres), "GetDisplayName failed %08lx\n", hres);
335     ok(!lstrcmpW(display_name, WINE_ABOUT_URL), "GetDisplayName got wrong name\n");
336
337     hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk);
338     ok(SUCCEEDED(hres), "IMoniker_BindToStorage failed: %08lx\n", hres);
339     todo_wine {
340         ok(unk == NULL, "istr should be NULL\n");
341     }
342     if(FAILED(hres)) {
343         IBindStatusCallback_Release(sclb);
344         IMoniker_Release(mon);
345         return;
346     }
347     if(unk)
348         IUnknown_Release(unk);
349
350     while(!stopped_binding && GetMessage(&msg,NULL,0,0)) {
351         TranslateMessage(&msg);
352         DispatchMessage(&msg);
353     }
354
355     ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
356     ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
357     ok(IBindStatusCallback_Release(sclb) == 0, "scbl should be destroyed here\n");
358 }
359
360 START_TEST(url)
361 {
362     test_create();
363     test_CreateAsyncBindCtx();
364     test_CreateAsyncBindCtxEx();
365     test_BindToStorage();
366 }