push d2ed94b6221baa59db3b40852d651a773c374f7d
[wine/hacks.git] / dlls / urlmon / bindprot.c
blob1f245943b3bf674e706249682d5c7a42b73f5f12
1 /*
2 * Copyright 2007 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
24 typedef struct {
25 const IInternetProtocolVtbl *lpInternetProtocolVtbl;
26 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
27 const IInternetPriorityVtbl *lpInternetPriorityVtbl;
28 const IServiceProviderVtbl *lpServiceProviderVtbl;
29 const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
31 LONG ref;
33 IInternetProtocol *protocol;
34 IInternetBindInfo *bind_info;
35 IInternetProtocolSink *protocol_sink;
36 IServiceProvider *service_provider;
37 IWinInetInfo *wininet_info;
39 LONG priority;
41 BOOL reported_result;
42 BOOL from_urlmon;
43 } BindProtocol;
45 #define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
46 #define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
47 #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
48 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
49 #define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
51 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface)
53 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
55 BindProtocol *This = PROTOCOL_THIS(iface);
57 *ppv = NULL;
58 if(IsEqualGUID(&IID_IUnknown, riid)) {
59 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
60 *ppv = PROTOCOL(This);
61 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
62 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
63 *ppv = PROTOCOL(This);
64 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
65 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
66 *ppv = PROTOCOL(This);
67 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
68 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
69 *ppv = BINDINFO(This);
70 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
71 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
72 *ppv = PRIORITY(This);
73 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
74 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
75 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
76 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
77 *ppv = SERVPROV(This);
78 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
79 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
80 *ppv = PROTSINK(This);
83 if(*ppv) {
84 IInternetProtocol_AddRef(iface);
85 return S_OK;
88 WARN("not supported interface %s\n", debugstr_guid(riid));
89 return E_NOINTERFACE;
92 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
94 BindProtocol *This = PROTOCOL_THIS(iface);
95 LONG ref = InterlockedIncrement(&This->ref);
96 TRACE("(%p) ref=%d\n", This, ref);
97 return ref;
100 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
102 BindProtocol *This = PROTOCOL_THIS(iface);
103 LONG ref = InterlockedDecrement(&This->ref);
105 TRACE("(%p) ref=%d\n", This, ref);
107 if(!ref) {
108 if(This->wininet_info)
109 IWinInetInfo_Release(This->wininet_info);
110 if(This->protocol)
111 IInternetProtocol_Release(This->protocol);
112 if(This->bind_info)
113 IInternetBindInfo_Release(This->bind_info);
115 set_binding_sink(PROTOCOL(This), NULL);
116 heap_free(This);
118 URLMON_UnlockModule();
121 return ref;
124 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
125 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
126 DWORD grfPI, HANDLE_PTR dwReserved)
128 BindProtocol *This = PROTOCOL_THIS(iface);
129 IInternetProtocol *protocol = NULL;
130 IInternetPriority *priority;
131 IServiceProvider *service_provider;
132 BOOL urlmon_protocol = FALSE;
133 CLSID clsid = IID_NULL;
134 LPOLESTR clsid_str;
135 HRESULT hres;
137 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
138 pOIBindInfo, grfPI, dwReserved);
140 if(!szUrl || !pOIProtSink || !pOIBindInfo)
141 return E_INVALIDARG;
143 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
144 (void**)&service_provider);
145 if(SUCCEEDED(hres)) {
146 /* FIXME: What's protocol CLSID here? */
147 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
148 &IID_IInternetProtocol, (void**)&protocol);
149 IServiceProvider_Release(service_provider);
152 if(!protocol) {
153 IClassFactory *cf;
154 IUnknown *unk;
156 hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
157 if(FAILED(hres))
158 return hres;
160 if(This->from_urlmon) {
161 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
162 IClassFactory_Release(cf);
163 if(FAILED(hres))
164 return hres;
165 }else {
166 hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
167 &IID_IUnknown, (void**)&unk);
168 IClassFactory_Release(cf);
169 if(FAILED(hres))
170 return hres;
172 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
173 IUnknown_Release(unk);
174 if(FAILED(hres))
175 return hres;
179 StringFromCLSID(&clsid, &clsid_str);
180 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
181 CoTaskMemFree(clsid_str);
183 This->protocol = protocol;
185 if(urlmon_protocol)
186 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
188 IInternetBindInfo_AddRef(pOIBindInfo);
189 This->bind_info = pOIBindInfo;
191 set_binding_sink(PROTOCOL(This), pOIProtSink);
193 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
194 if(SUCCEEDED(hres)) {
195 IInternetPriority_SetPriority(priority, This->priority);
196 IInternetPriority_Release(priority);
199 return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
202 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
204 BindProtocol *This = PROTOCOL_THIS(iface);
206 TRACE("(%p)->(%p)\n", This, pProtocolData);
208 return IInternetProtocol_Continue(This->protocol, pProtocolData);
211 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
212 DWORD dwOptions)
214 BindProtocol *This = PROTOCOL_THIS(iface);
215 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
216 return E_NOTIMPL;
219 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
221 BindProtocol *This = PROTOCOL_THIS(iface);
223 TRACE("(%p)->(%08x)\n", This, dwOptions);
225 if(!This->reported_result)
226 return E_FAIL;
228 IInternetProtocol_Terminate(This->protocol, 0);
230 set_binding_sink(PROTOCOL(This), NULL);
232 if(This->bind_info) {
233 IInternetBindInfo_Release(This->bind_info);
234 This->bind_info = NULL;
237 return S_OK;
240 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
242 BindProtocol *This = PROTOCOL_THIS(iface);
243 FIXME("(%p)\n", This);
244 return E_NOTIMPL;
247 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
249 BindProtocol *This = PROTOCOL_THIS(iface);
250 FIXME("(%p)\n", This);
251 return E_NOTIMPL;
254 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
255 ULONG cb, ULONG *pcbRead)
257 BindProtocol *This = PROTOCOL_THIS(iface);
258 ULONG read = 0;
259 HRESULT hres;
261 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
263 hres = IInternetProtocol_Read(This->protocol, pv, cb, &read);
265 *pcbRead = read;
266 return hres;
269 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
270 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
272 BindProtocol *This = PROTOCOL_THIS(iface);
273 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
274 return E_NOTIMPL;
277 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
279 BindProtocol *This = PROTOCOL_THIS(iface);
281 TRACE("(%p)->(%08x)\n", This, dwOptions);
283 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
286 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
288 BindProtocol *This = PROTOCOL_THIS(iface);
290 TRACE("(%p)\n", This);
292 return IInternetProtocol_UnlockRequest(This->protocol);
295 void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
297 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
298 IInternetProtocolSink *prev_sink;
299 IServiceProvider *service_provider = NULL;
301 if(sink)
302 IInternetProtocolSink_AddRef(sink);
303 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
304 if(prev_sink)
305 IInternetProtocolSink_Release(prev_sink);
307 if(sink)
308 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
309 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
310 if(service_provider)
311 IServiceProvider_Release(service_provider);
314 IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
316 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
318 return This->wininet_info;
321 #undef PROTOCOL_THIS
323 static const IInternetProtocolVtbl BindProtocolVtbl = {
324 BindProtocol_QueryInterface,
325 BindProtocol_AddRef,
326 BindProtocol_Release,
327 BindProtocol_Start,
328 BindProtocol_Continue,
329 BindProtocol_Abort,
330 BindProtocol_Terminate,
331 BindProtocol_Suspend,
332 BindProtocol_Resume,
333 BindProtocol_Read,
334 BindProtocol_Seek,
335 BindProtocol_LockRequest,
336 BindProtocol_UnlockRequest
339 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
341 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
342 REFIID riid, void **ppv)
344 BindProtocol *This = BINDINFO_THIS(iface);
345 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
348 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
350 BindProtocol *This = BINDINFO_THIS(iface);
351 return IBinding_AddRef(PROTOCOL(This));
354 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
356 BindProtocol *This = BINDINFO_THIS(iface);
357 return IBinding_Release(PROTOCOL(This));
360 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
361 DWORD *grfBINDF, BINDINFO *pbindinfo)
363 BindProtocol *This = BINDINFO_THIS(iface);
364 HRESULT hres;
366 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
368 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
369 if(FAILED(hres)) {
370 WARN("GetBindInfo failed: %08x\n", hres);
371 return hres;
374 *grfBINDF |= BINDF_FROMURLMON;
375 return hres;
378 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
379 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
381 BindProtocol *This = BINDINFO_THIS(iface);
383 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
385 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
388 #undef BINDFO_THIS
390 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
391 BindInfo_QueryInterface,
392 BindInfo_AddRef,
393 BindInfo_Release,
394 BindInfo_GetBindInfo,
395 BindInfo_GetBindString
398 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
400 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
401 REFIID riid, void **ppv)
403 BindProtocol *This = PRIORITY_THIS(iface);
404 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
407 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
409 BindProtocol *This = PRIORITY_THIS(iface);
410 return IInternetProtocol_AddRef(PROTOCOL(This));
413 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
415 BindProtocol *This = PRIORITY_THIS(iface);
416 return IInternetProtocol_Release(PROTOCOL(This));
419 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
421 BindProtocol *This = PRIORITY_THIS(iface);
423 TRACE("(%p)->(%d)\n", This, nPriority);
425 This->priority = nPriority;
426 return S_OK;
429 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
431 BindProtocol *This = PRIORITY_THIS(iface);
433 TRACE("(%p)->(%p)\n", This, pnPriority);
435 *pnPriority = This->priority;
436 return S_OK;
439 #undef PRIORITY_THIS
441 static const IInternetPriorityVtbl InternetPriorityVtbl = {
442 InternetPriority_QueryInterface,
443 InternetPriority_AddRef,
444 InternetPriority_Release,
445 InternetPriority_SetPriority,
446 InternetPriority_GetPriority
450 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface)
452 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
453 REFIID riid, void **ppv)
455 BindProtocol *This = PROTSINK_THIS(iface);
456 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
459 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
461 BindProtocol *This = PROTSINK_THIS(iface);
462 return IInternetProtocol_AddRef(PROTOCOL(This));
465 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
467 BindProtocol *This = PROTSINK_THIS(iface);
468 return IInternetProtocol_Release(PROTOCOL(This));
471 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
472 PROTOCOLDATA *pProtocolData)
474 BindProtocol *This = PROTSINK_THIS(iface);
476 TRACE("(%p)->(%p)\n", This, pProtocolData);
478 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
479 pProtocolData->pData, pProtocolData->cbData);
481 if(!This->protocol_sink) {
482 IInternetProtocol_Continue(This->protocol, pProtocolData);
483 return S_OK;
486 return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
489 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
490 ULONG ulStatusCode, LPCWSTR szStatusText)
492 BindProtocol *This = PROTSINK_THIS(iface);
494 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
496 switch(ulStatusCode) {
497 case BINDSTATUS_FINDINGRESOURCE:
498 case BINDSTATUS_CONNECTING:
499 case BINDSTATUS_BEGINDOWNLOADDATA:
500 case BINDSTATUS_SENDINGREQUEST:
501 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
502 case BINDSTATUS_DIRECTBIND:
503 case BINDSTATUS_ACCEPTRANGES:
504 case BINDSTATUS_MIMETYPEAVAILABLE:
505 if(!This->protocol_sink)
506 return S_OK;
507 return IInternetProtocolSink_ReportProgress(This->protocol_sink,
508 ulStatusCode, szStatusText);
510 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
511 if(!This->protocol_sink)
512 return S_OK;
513 return IInternetProtocolSink_ReportProgress(This->protocol_sink,
514 This->from_urlmon ? BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE,
515 szStatusText);
516 default:
517 FIXME("unsupported ulStatusCode %u\n", ulStatusCode);
520 return E_NOTIMPL;
523 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
524 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
526 BindProtocol *This = PROTSINK_THIS(iface);
528 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
530 if(!This->protocol_sink)
531 return S_OK;
533 return IInternetProtocolSink_ReportData(This->protocol_sink, grfBSCF, ulProgress, ulProgressMax);
536 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
537 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
539 BindProtocol *This = PROTSINK_THIS(iface);
541 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
543 if(!This->protocol_sink)
544 return E_FAIL;
546 This->reported_result = TRUE;
548 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
551 #undef PROTSINK_THIS
553 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
554 BPInternetProtocolSink_QueryInterface,
555 BPInternetProtocolSink_AddRef,
556 BPInternetProtocolSink_Release,
557 BPInternetProtocolSink_Switch,
558 BPInternetProtocolSink_ReportProgress,
559 BPInternetProtocolSink_ReportData,
560 BPInternetProtocolSink_ReportResult
563 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
565 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
566 REFIID riid, void **ppv)
568 BindProtocol *This = SERVPROV_THIS(iface);
569 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
572 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
574 BindProtocol *This = SERVPROV_THIS(iface);
575 return IInternetProtocol_AddRef(PROTOCOL(This));
578 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
580 BindProtocol *This = SERVPROV_THIS(iface);
581 return IInternetProtocol_Release(PROTOCOL(This));
584 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
585 REFGUID guidService, REFIID riid, void **ppv)
587 BindProtocol *This = SERVPROV_THIS(iface);
589 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
591 if(!This->service_provider)
592 return E_NOINTERFACE;
594 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
597 #undef SERVPROV_THIS
599 static const IServiceProviderVtbl ServiceProviderVtbl = {
600 BPServiceProvider_QueryInterface,
601 BPServiceProvider_AddRef,
602 BPServiceProvider_Release,
603 BPServiceProvider_QueryService
606 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
608 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
610 ret->lpInternetProtocolVtbl = &BindProtocolVtbl;
611 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
612 ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
613 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
614 ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
616 ret->ref = 1;
617 ret->from_urlmon = from_urlmon;
619 URLMON_LockModule();
621 *protocol = PROTOCOL(ret);
622 return S_OK;