msi: Return ERROR_INVALID_PARAMETER if the product list is empty and index is not...
[wine] / dlls / urlmon / bindprot.c
1 /*
2  * Copyright 2007 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
23
24 typedef struct {
25     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
26     const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
27     const IInternetPriorityVtbl *lpInternetPriorityVtbl;
28     const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
29
30     LONG ref;
31
32     IInternetProtocol *protocol;
33     IInternetBindInfo *bind_info;
34     IInternetProtocolSink *protocol_sink;
35
36     LONG priority;
37 } BindProtocol;
38
39 #define PROTOCOL(x)  ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
40 #define BINDINFO(x)  ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
41 #define PRIORITY(x)  ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
42 #define PROTSINK(x)  ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
43
44 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface)
45
46 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
47 {
48     BindProtocol *This = PROTOCOL_THIS(iface);
49
50     *ppv = NULL;
51     if(IsEqualGUID(&IID_IUnknown, riid)) {
52         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
53         *ppv = PROTOCOL(This);
54     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
55         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
56         *ppv = PROTOCOL(This);
57     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
58         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
59         *ppv = PROTOCOL(This);
60     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
61         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
62         *ppv = BINDINFO(This);
63     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
64         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
65         *ppv = PRIORITY(This);
66     }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
67         FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
68     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
69         FIXME("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
70     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
71         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
72         *ppv = PROTSINK(This);
73     }
74
75     if(*ppv) {
76         IInternetProtocol_AddRef(iface);
77         return S_OK;
78     }
79
80     WARN("not supported interface %s\n", debugstr_guid(riid));
81     return E_NOINTERFACE;
82 }
83
84 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
85 {
86     BindProtocol *This = PROTOCOL_THIS(iface);
87     LONG ref = InterlockedIncrement(&This->ref);
88     TRACE("(%p) ref=%d\n", This, ref);
89     return ref;
90 }
91
92 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
93 {
94     BindProtocol *This = PROTOCOL_THIS(iface);
95     LONG ref = InterlockedDecrement(&This->ref);
96
97     TRACE("(%p) ref=%d\n", This, ref);
98
99     if(!ref) {
100         if(This->protocol)
101             IInternetProtocol_Release(This->protocol);
102         if(This->bind_info)
103             IInternetBindInfo_Release(This->bind_info);
104         if(This->protocol_sink)
105             IInternetProtocolSink_Release(This->protocol_sink);
106
107         heap_free(This);
108
109         URLMON_UnlockModule();
110     }
111
112     return ref;
113 }
114
115 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
116         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
117         DWORD grfPI, DWORD dwReserved)
118 {
119     BindProtocol *This = PROTOCOL_THIS(iface);
120     IInternetProtocol *protocol = NULL;
121     IInternetPriority *priority;
122     IServiceProvider *service_provider;
123     CLSID clsid = IID_NULL;
124     LPOLESTR clsid_str;
125     HRESULT hres;
126
127     TRACE("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink,
128             pOIBindInfo, grfPI, dwReserved);
129
130     if(!szUrl || !pOIProtSink || !pOIBindInfo)
131         return E_INVALIDARG;
132
133     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
134                                                 (void**)&service_provider);
135     if(SUCCEEDED(hres)) {
136         /* FIXME: What's protocol CLSID here? */
137         IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
138                                       &IID_IInternetProtocol, (void**)&protocol);
139         IServiceProvider_Release(service_provider);
140     }
141
142     if(!protocol) {
143         IClassFactory *cf;
144         IUnknown *unk;
145
146         hres = get_protocol_handler(szUrl, &clsid, &cf);
147         if(FAILED(hres))
148             return hres;
149
150         hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
151                 &IID_IUnknown, (void**)&unk);
152         IClassFactory_Release(cf);
153         if(FAILED(hres))
154             return hres;
155
156         hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
157         IUnknown_Release(unk);
158         if(FAILED(hres))
159             return hres;
160     }
161
162     StringFromCLSID(&clsid, &clsid_str);
163     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
164     CoTaskMemFree(clsid_str);
165
166     This->protocol = protocol;
167
168     IInternetBindInfo_AddRef(pOIBindInfo);
169     This->bind_info = pOIBindInfo;
170
171     IInternetProtocolSink_AddRef(pOIProtSink);
172     This->protocol_sink = pOIProtSink;
173
174     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
175     if(SUCCEEDED(hres)) {
176         IInternetPriority_SetPriority(priority, This->priority);
177         IInternetPriority_Release(priority);
178     }
179
180     return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
181 }
182
183 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
184 {
185     BindProtocol *This = PROTOCOL_THIS(iface);
186     FIXME("(%p)->(%p)\n", This, pProtocolData);
187     return E_NOTIMPL;
188 }
189
190 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
191         DWORD dwOptions)
192 {
193     BindProtocol *This = PROTOCOL_THIS(iface);
194     FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
195     return E_NOTIMPL;
196 }
197
198 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
199 {
200     BindProtocol *This = PROTOCOL_THIS(iface);
201
202     TRACE("(%p)->(%08x)\n", This, dwOptions);
203
204     IInternetProtocol_Terminate(This->protocol, 0);
205     return S_OK;
206 }
207
208 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
209 {
210     BindProtocol *This = PROTOCOL_THIS(iface);
211     FIXME("(%p)\n", This);
212     return E_NOTIMPL;
213 }
214
215 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
216 {
217     BindProtocol *This = PROTOCOL_THIS(iface);
218     FIXME("(%p)\n", This);
219     return E_NOTIMPL;
220 }
221
222 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
223         ULONG cb, ULONG *pcbRead)
224 {
225     BindProtocol *This = PROTOCOL_THIS(iface);
226     ULONG read = 0;
227     HRESULT hres;
228
229     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
230
231     hres = IInternetProtocol_Read(This->protocol, pv, cb, &read);
232
233     *pcbRead = read;
234     return hres;
235 }
236
237 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
238         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
239 {
240     BindProtocol *This = PROTOCOL_THIS(iface);
241     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
242     return E_NOTIMPL;
243 }
244
245 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
246 {
247     BindProtocol *This = PROTOCOL_THIS(iface);
248     FIXME("(%p)->(%08x)\n", This, dwOptions);
249     return E_NOTIMPL;
250 }
251
252 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
253 {
254     BindProtocol *This = PROTOCOL_THIS(iface);
255     FIXME("(%p)\n", This);
256     return E_NOTIMPL;
257 }
258
259 #undef PROTOCOL_THIS
260
261 static const IInternetProtocolVtbl BindProtocolVtbl = {
262     BindProtocol_QueryInterface,
263     BindProtocol_AddRef,
264     BindProtocol_Release,
265     BindProtocol_Start,
266     BindProtocol_Continue,
267     BindProtocol_Abort,
268     BindProtocol_Terminate,
269     BindProtocol_Suspend,
270     BindProtocol_Resume,
271     BindProtocol_Read,
272     BindProtocol_Seek,
273     BindProtocol_LockRequest,
274     BindProtocol_UnlockRequest
275 };
276
277 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
278
279 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
280         REFIID riid, void **ppv)
281 {
282     BindProtocol *This = BINDINFO_THIS(iface);
283     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
284 }
285
286 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
287 {
288     BindProtocol *This = BINDINFO_THIS(iface);
289     return IBinding_AddRef(PROTOCOL(This));
290 }
291
292 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
293 {
294     BindProtocol *This = BINDINFO_THIS(iface);
295     return IBinding_Release(PROTOCOL(This));
296 }
297
298 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
299         DWORD *grfBINDF, BINDINFO *pbindinfo)
300 {
301     BindProtocol *This = BINDINFO_THIS(iface);
302     HRESULT hres;
303
304     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
305
306     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
307     if(FAILED(hres)) {
308         WARN("GetBindInfo failed: %08x\n", hres);
309         return hres;
310     }
311
312     *grfBINDF |= BINDF_FROMURLMON;
313     return hres;
314 }
315
316 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
317         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
318 {
319     BindProtocol *This = BINDINFO_THIS(iface);
320     FIXME("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
321     return E_NOTIMPL;
322 }
323
324 #undef BINDFO_THIS
325
326 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
327     BindInfo_QueryInterface,
328     BindInfo_AddRef,
329     BindInfo_Release,
330     BindInfo_GetBindInfo,
331     BindInfo_GetBindString
332 };
333
334 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
335
336 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
337         REFIID riid, void **ppv)
338 {
339     BindProtocol *This = PRIORITY_THIS(iface);
340     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
341 }
342
343 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
344 {
345     BindProtocol *This = PRIORITY_THIS(iface);
346     return IInternetProtocol_AddRef(PROTOCOL(This));
347 }
348
349 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
350 {
351     BindProtocol *This = PRIORITY_THIS(iface);
352     return IInternetProtocol_Release(PROTOCOL(This));
353 }
354
355 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
356 {
357     BindProtocol *This = PRIORITY_THIS(iface);
358
359     TRACE("(%p)->(%d)\n", This, nPriority);
360
361     This->priority = nPriority;
362     return S_OK;
363 }
364
365 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
366 {
367     BindProtocol *This = PRIORITY_THIS(iface);
368
369     TRACE("(%p)->(%p)\n", This, pnPriority);
370
371     *pnPriority = This->priority;
372     return S_OK;
373 }
374
375 #undef PRIORITY_THIS
376
377 static const IInternetPriorityVtbl InternetPriorityVtbl = {
378     InternetPriority_QueryInterface,
379     InternetPriority_AddRef,
380     InternetPriority_Release,
381     InternetPriority_SetPriority,
382     InternetPriority_GetPriority
383
384 };
385
386 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface)
387
388 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
389         REFIID riid, void **ppv)
390 {
391     BindProtocol *This = PROTSINK_THIS(iface);
392     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
393 }
394
395 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
396 {
397     BindProtocol *This = PROTSINK_THIS(iface);
398     return IInternetProtocol_AddRef(PROTOCOL(This));
399 }
400
401 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
402 {
403     BindProtocol *This = PROTSINK_THIS(iface);
404     return IInternetProtocol_Release(PROTOCOL(This));
405 }
406
407 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
408         PROTOCOLDATA *pProtocolData)
409 {
410     BindProtocol *This = PROTSINK_THIS(iface);
411     FIXME("(%p)->(%p)\n", This, pProtocolData);
412     return E_NOTIMPL;
413 }
414
415 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
416         ULONG ulStatusCode, LPCWSTR szStatusText)
417 {
418     BindProtocol *This = PROTSINK_THIS(iface);
419
420     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
421
422     switch(ulStatusCode) {
423     case BINDSTATUS_SENDINGREQUEST:
424         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
425                 ulStatusCode, NULL);
426     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
427         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
428                 ulStatusCode, szStatusText);
429     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
430         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
431                 BINDSTATUS_MIMETYPEAVAILABLE, szStatusText);
432     default:
433         FIXME("unsupported ulStatusCode %u\n", ulStatusCode);
434     }
435
436     return E_NOTIMPL;
437 }
438
439 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
440         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
441 {
442     BindProtocol *This = PROTSINK_THIS(iface);
443
444     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
445
446     return S_OK;
447 }
448
449 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
450         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
451 {
452     BindProtocol *This = PROTSINK_THIS(iface);
453
454     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
455
456     return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
457 }
458
459 #undef PROTSINK_THIS
460
461 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
462     InternetProtocolSink_QueryInterface,
463     InternetProtocolSink_AddRef,
464     InternetProtocolSink_Release,
465     InternetProtocolSink_Switch,
466     InternetProtocolSink_ReportProgress,
467     InternetProtocolSink_ReportData,
468     InternetProtocolSink_ReportResult
469 };
470
471 HRESULT create_binding_protocol(LPCWSTR url, IInternetProtocol **protocol)
472 {
473     BindProtocol *ret = heap_alloc(sizeof(BindProtocol));
474
475     ret->lpInternetProtocolVtbl = &BindProtocolVtbl;
476     ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
477     ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
478     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
479
480     ret->ref = 1;
481     ret->protocol = NULL;
482     ret->bind_info = NULL;
483     ret->protocol_sink = NULL;
484     ret->priority = 0;
485
486     URLMON_LockModule();
487
488     *protocol = PROTOCOL(ret);
489     return S_OK;
490 }