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