ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

binding.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2005-2007 Jacek Caban for CodeWeavers
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include "urlmon_main.h"
00020 #include "winreg.h"
00021 #include "shlwapi.h"
00022 
00023 #include "wine/debug.h"
00024 
00025 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
00026 
00027 static WCHAR cbinding_contextW[] = {'C','B','i','n','d','i','n','g',' ','C','o','n','t','e','x','t',0};
00028 static WCHAR bscb_holderW[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
00029 
00030 typedef struct {
00031     IUnknown IUnknown_iface;
00032 
00033     LONG ref;
00034 
00035     IInternetProtocolEx *protocol;
00036 
00037     HANDLE file;
00038     HRESULT hres;
00039 
00040     LPWSTR cache_file;
00041 } stgmed_buf_t;
00042 
00043 typedef struct _stgmed_obj_t stgmed_obj_t;
00044 
00045 typedef struct {
00046     void (*release)(stgmed_obj_t*);
00047     HRESULT (*fill_stgmed)(stgmed_obj_t*,STGMEDIUM*);
00048     HRESULT (*get_result)(stgmed_obj_t*,DWORD,void**);
00049 } stgmed_obj_vtbl;
00050 
00051 struct _stgmed_obj_t {
00052     const stgmed_obj_vtbl *vtbl;
00053 };
00054 
00055 typedef enum {
00056     BEFORE_DOWNLOAD,
00057     DOWNLOADING,
00058     END_DOWNLOAD
00059 } download_state_t;
00060 
00061 #define BINDING_LOCKED    0x0001
00062 #define BINDING_STOPPED   0x0002
00063 #define BINDING_OBJAVAIL  0x0004
00064 #define BINDING_ABORTED   0x0008
00065 
00066 typedef struct {
00067     IBinding              IBinding_iface;
00068     IInternetProtocolSink IInternetProtocolSink_iface;
00069     IInternetBindInfo     IInternetBindInfo_iface;
00070     IWinInetHttpInfo      IWinInetHttpInfo_iface;
00071     IServiceProvider      IServiceProvider_iface;
00072 
00073     LONG ref;
00074 
00075     IBindStatusCallback *callback;
00076     IServiceProvider *service_provider;
00077 
00078     BindProtocol *protocol;
00079 
00080     stgmed_buf_t *stgmed_buf;
00081     stgmed_obj_t *stgmed_obj;
00082 
00083     BINDINFO bindinfo;
00084     DWORD bindf;
00085     BOOL to_object;
00086     LPWSTR mime;
00087     UINT clipboard_format;
00088     LPWSTR url;
00089     LPWSTR redirect_url;
00090     IID iid;
00091     BOOL report_mime;
00092     BOOL use_cache_file;
00093     DWORD state;
00094     HRESULT hres;
00095     download_state_t download_state;
00096     IUnknown *obj;
00097     IMoniker *mon;
00098     IBindCtx *bctx;
00099     HWND notif_hwnd;
00100 
00101     CRITICAL_SECTION section;
00102 } Binding;
00103 
00104 static void read_protocol_data(stgmed_buf_t *stgmed_buf)
00105 {
00106     BYTE buf[8192];
00107     DWORD read;
00108     HRESULT hres;
00109 
00110     do hres = IInternetProtocol_Read(stgmed_buf->protocol, buf, sizeof(buf), &read);
00111     while(hres == S_OK);
00112 }
00113 
00114 static void dump_BINDINFO(BINDINFO *bi)
00115 {
00116     static const char * const BINDINFOF_str[] = {
00117         "#0",
00118         "BINDINFOF_URLENCODESTGMEDDATA",
00119         "BINDINFOF_URLENCODEDEXTRAINFO"
00120     };
00121 
00122     static const char * const BINDVERB_str[] = {
00123         "BINDVERB_GET",
00124         "BINDVERB_POST",
00125         "BINDVERB_PUT",
00126         "BINDVERB_CUSTOM"
00127     };
00128 
00129     TRACE("\n"
00130             "BINDINFO = {\n"
00131             "    %d, %s,\n"
00132             "    {%d, %p, %p},\n"
00133             "    %s,\n"
00134             "    %s,\n"
00135             "    %s,\n"
00136             "    %d, %08x, %d, %d\n"
00137             "    {%d %p %x},\n"
00138             "    %s\n"
00139             "    %p, %d\n"
00140             "}\n",
00141 
00142             bi->cbSize, debugstr_w(bi->szExtraInfo),
00143             bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
00144             bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
00145                 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
00146             bi->dwBindVerb > BINDVERB_CUSTOM
00147                 ? "unknown" : BINDVERB_str[bi->dwBindVerb],
00148             debugstr_w(bi->szCustomVerb),
00149             bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
00150             bi->securityAttributes.nLength,
00151             bi->securityAttributes.lpSecurityDescriptor,
00152             bi->securityAttributes.bInheritHandle,
00153             debugstr_guid(&bi->iid),
00154             bi->pUnk, bi->dwReserved
00155             );
00156 }
00157 
00158 static void mime_available(Binding *This, LPCWSTR mime)
00159 {
00160     heap_free(This->mime);
00161     This->mime = heap_strdupW(mime);
00162 
00163     if(!This->mime || !This->report_mime)
00164         return;
00165 
00166     IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
00167 
00168     This->clipboard_format = RegisterClipboardFormatW(This->mime);
00169 }
00170 
00171 static void stop_binding(Binding *binding, HRESULT hres, LPCWSTR str)
00172 {
00173     if(binding->state & BINDING_LOCKED) {
00174         IInternetProtocolEx_UnlockRequest(&binding->protocol->IInternetProtocolEx_iface);
00175         binding->state &= ~BINDING_LOCKED;
00176     }
00177 
00178     if(!(binding->state & BINDING_STOPPED)) {
00179         binding->state |= BINDING_STOPPED;
00180 
00181         IBindStatusCallback_OnStopBinding(binding->callback, hres, str);
00182         binding->hres = hres;
00183     }
00184 }
00185 
00186 static LPWSTR get_mime_clsid(LPCWSTR mime, CLSID *clsid)
00187 {
00188     LPWSTR key_name, ret;
00189     DWORD res, type, size;
00190     HKEY hkey;
00191     int len;
00192     HRESULT hres;
00193 
00194     static const WCHAR mime_keyW[] =
00195         {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
00196          'C','o','n','t','e','n','t',' ','T','y','p','e','\\'};
00197     static const WCHAR clsidW[] = {'C','L','S','I','D',0};
00198 
00199     len = strlenW(mime)+1;
00200     key_name = heap_alloc(sizeof(mime_keyW) + len*sizeof(WCHAR));
00201     memcpy(key_name, mime_keyW, sizeof(mime_keyW));
00202     strcpyW(key_name + sizeof(mime_keyW)/sizeof(WCHAR), mime);
00203 
00204     res = RegOpenKeyW(HKEY_CLASSES_ROOT, key_name, &hkey);
00205     heap_free(key_name);
00206     if(res != ERROR_SUCCESS) {
00207         WARN("Could not open MIME key: %x\n", res);
00208         return NULL;
00209     }
00210 
00211     size = 50*sizeof(WCHAR);
00212     ret = heap_alloc(size);
00213     res = RegQueryValueExW(hkey, clsidW, NULL, &type, (LPBYTE)ret, &size);
00214     RegCloseKey(hkey);
00215     if(res != ERROR_SUCCESS) {
00216         WARN("Could not get CLSID: %08x\n", res);
00217         heap_free(ret);
00218         return NULL;
00219     }
00220 
00221     hres = CLSIDFromString(ret, clsid);
00222     if(FAILED(hres)) {
00223         WARN("Could not parse CLSID: %08x\n", hres);
00224         heap_free(ret);
00225         return NULL;
00226     }
00227 
00228     return ret;
00229 }
00230 
00231 static void load_doc_mon(Binding *binding, IPersistMoniker *persist)
00232 {
00233     IBindCtx *bctx;
00234     HRESULT hres;
00235 
00236     hres = CreateAsyncBindCtxEx(binding->bctx, 0, NULL, NULL, &bctx, 0);
00237     if(FAILED(hres)) {
00238         WARN("CreateAsyncBindCtxEx failed: %08x\n", hres);
00239         return;
00240     }
00241 
00242     IBindCtx_RevokeObjectParam(bctx, bscb_holderW);
00243     IBindCtx_RegisterObjectParam(bctx, cbinding_contextW, (IUnknown*)&binding->IBinding_iface);
00244 
00245     hres = IPersistMoniker_Load(persist, binding->download_state == END_DOWNLOAD, binding->mon, bctx, 0x12);
00246     IBindCtx_RevokeObjectParam(bctx, cbinding_contextW);
00247     IBindCtx_Release(bctx);
00248     if(FAILED(hres))
00249         FIXME("Load failed: %08x\n", hres);
00250 }
00251 
00252 static HRESULT create_mime_object(Binding *binding, const CLSID *clsid, LPCWSTR clsid_str)
00253 {
00254     IPersistMoniker *persist;
00255     HRESULT hres;
00256 
00257     hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
00258                             &binding->iid, (void**)&binding->obj);
00259     if(FAILED(hres)) {
00260         WARN("CoCreateInstance failed: %08x\n", hres);
00261         return INET_E_CANNOT_INSTANTIATE_OBJECT;
00262     }
00263 
00264     binding->state |= BINDING_OBJAVAIL;
00265 
00266     hres = IUnknown_QueryInterface(binding->obj, &IID_IPersistMoniker, (void**)&persist);
00267     if(SUCCEEDED(hres)) {
00268         IMonikerProp *prop;
00269 
00270         hres = IPersistMoniker_QueryInterface(persist, &IID_IMonikerProp, (void**)&prop);
00271         if(SUCCEEDED(hres)) {
00272             IMonikerProp_PutProperty(prop, MIMETYPEPROP, binding->mime);
00273             IMonikerProp_PutProperty(prop, CLASSIDPROP, clsid_str);
00274             IMonikerProp_Release(prop);
00275         }
00276 
00277         load_doc_mon(binding, persist);
00278 
00279         IPersistMoniker_Release(persist);
00280     }else {
00281         FIXME("Could not get IPersistMoniker: %08x\n", hres);
00282         /* FIXME: Try query IPersistFile */
00283     }
00284 
00285     IBindStatusCallback_OnObjectAvailable(binding->callback, &binding->iid, binding->obj);
00286 
00287     return S_OK;
00288 }
00289 
00290 static void create_object(Binding *binding)
00291 {
00292     LPWSTR clsid_str;
00293     CLSID clsid;
00294     HRESULT hres;
00295 
00296     if(!binding->mime) {
00297         FIXME("MIME not available\n");
00298         return;
00299     }
00300 
00301     if(!(clsid_str = get_mime_clsid(binding->mime, &clsid))) {
00302         FIXME("Could not find object for MIME %s\n", debugstr_w(binding->mime));
00303         return;
00304     }
00305 
00306     IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_CLASSIDAVAILABLE, clsid_str);
00307     IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_BEGINSYNCOPERATION, NULL);
00308 
00309     hres = create_mime_object(binding, &clsid, clsid_str);
00310     heap_free(clsid_str);
00311 
00312     IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_ENDSYNCOPERATION, NULL);
00313 
00314     stop_binding(binding, hres, NULL);
00315     if(FAILED(hres))
00316         IInternetProtocolEx_Terminate(&binding->protocol->IInternetProtocolEx_iface, 0);
00317 }
00318 
00319 static void cache_file_available(Binding *This, const WCHAR *file_name)
00320 {
00321     heap_free(This->stgmed_buf->cache_file);
00322     This->stgmed_buf->cache_file = heap_strdupW(file_name);
00323 
00324     if(This->use_cache_file) {
00325         This->stgmed_buf->file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
00326                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
00327         if(This->stgmed_buf->file == INVALID_HANDLE_VALUE)
00328             WARN("CreateFile failed: %u\n", GetLastError());
00329     }
00330 }
00331 
00332 static inline stgmed_buf_t *impl_from_IUnknown(IUnknown *iface)
00333 {
00334     return CONTAINING_RECORD(iface, stgmed_buf_t, IUnknown_iface);
00335 }
00336 
00337 static HRESULT WINAPI StgMedUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
00338 {
00339     stgmed_buf_t *This = impl_from_IUnknown(iface);
00340 
00341     *ppv = NULL;
00342 
00343     if(IsEqualGUID(riid, &IID_IUnknown)) {
00344         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
00345 
00346         *ppv = &This->IUnknown_iface;
00347         IUnknown_AddRef(&This->IUnknown_iface);
00348         return S_OK;
00349     }
00350 
00351     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
00352     return E_NOINTERFACE;
00353 }
00354 
00355 static ULONG WINAPI StgMedUnk_AddRef(IUnknown *iface)
00356 {
00357     stgmed_buf_t *This = impl_from_IUnknown(iface);
00358     LONG ref = InterlockedIncrement(&This->ref);
00359 
00360     TRACE("(%p) ref=%d\n", This, ref);
00361 
00362     return ref;
00363 }
00364 
00365 static ULONG WINAPI StgMedUnk_Release(IUnknown *iface)
00366 {
00367     stgmed_buf_t *This = impl_from_IUnknown(iface);
00368     LONG ref = InterlockedDecrement(&This->ref);
00369 
00370     TRACE("(%p) ref=%d\n", This, ref);
00371 
00372     if(!ref) {
00373         if(This->file != INVALID_HANDLE_VALUE)
00374             CloseHandle(This->file);
00375         IInternetProtocol_Release(This->protocol);
00376         heap_free(This->cache_file);
00377         heap_free(This);
00378 
00379         URLMON_UnlockModule();
00380     }
00381 
00382     return ref;
00383 }
00384 
00385 static const IUnknownVtbl StgMedUnkVtbl = {
00386     StgMedUnk_QueryInterface,
00387     StgMedUnk_AddRef,
00388     StgMedUnk_Release
00389 };
00390 
00391 static stgmed_buf_t *create_stgmed_buf(IInternetProtocolEx *protocol)
00392 {
00393     stgmed_buf_t *ret = heap_alloc(sizeof(*ret));
00394 
00395     ret->IUnknown_iface.lpVtbl = &StgMedUnkVtbl;
00396     ret->ref = 1;
00397     ret->file = INVALID_HANDLE_VALUE;
00398     ret->hres = S_OK;
00399     ret->cache_file = NULL;
00400 
00401     IInternetProtocol_AddRef(protocol);
00402     ret->protocol = protocol;
00403 
00404     URLMON_LockModule();
00405 
00406     return ret;
00407 }
00408 
00409 typedef struct {
00410     stgmed_obj_t stgmed_obj;
00411     IStream IStream_iface;
00412 
00413     LONG ref;
00414 
00415     stgmed_buf_t *buf;
00416 } ProtocolStream;
00417 
00418 static inline ProtocolStream *impl_from_IStream(IStream *iface)
00419 {
00420     return CONTAINING_RECORD(iface, ProtocolStream, IStream_iface);
00421 }
00422 
00423 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
00424                                                           REFIID riid, void **ppv)
00425 {
00426     ProtocolStream *This = impl_from_IStream(iface);
00427 
00428     *ppv = NULL;
00429 
00430     if(IsEqualGUID(&IID_IUnknown, riid)) {
00431         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
00432         *ppv = &This->IStream_iface;
00433     }else if(IsEqualGUID(&IID_ISequentialStream, riid)) {
00434         TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv);
00435         *ppv = &This->IStream_iface;
00436     }else if(IsEqualGUID(&IID_IStream, riid)) {
00437         TRACE("(%p)->(IID_IStream %p)\n", This, ppv);
00438         *ppv = &This->IStream_iface;
00439     }
00440 
00441     if(*ppv) {
00442         IStream_AddRef(&This->IStream_iface);
00443         return S_OK;
00444     }
00445 
00446     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
00447     return E_NOINTERFACE;
00448 }
00449 
00450 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
00451 {
00452     ProtocolStream *This = impl_from_IStream(iface);
00453     LONG ref = InterlockedIncrement(&This->ref);
00454 
00455     TRACE("(%p) ref=%d\n", This, ref);
00456 
00457     return ref;
00458 }
00459 
00460 static ULONG WINAPI ProtocolStream_Release(IStream *iface)
00461 {
00462     ProtocolStream *This = impl_from_IStream(iface);
00463     LONG ref = InterlockedDecrement(&This->ref);
00464 
00465     TRACE("(%p) ref=%d\n", This, ref);
00466 
00467     if(!ref) {
00468         IUnknown_Release(&This->buf->IUnknown_iface);
00469         heap_free(This);
00470 
00471         URLMON_UnlockModule();
00472     }
00473 
00474     return ref;
00475 }
00476 
00477 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
00478                                           ULONG cb, ULONG *pcbRead)
00479 {
00480     ProtocolStream *This = impl_from_IStream(iface);
00481     DWORD read = 0;
00482     HRESULT hres;
00483 
00484     TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead);
00485 
00486     if(This->buf->file == INVALID_HANDLE_VALUE) {
00487         hres = This->buf->hres = IInternetProtocol_Read(This->buf->protocol, (PBYTE)pv, cb, &read);
00488     }else {
00489         hres = ReadFile(This->buf->file, pv, cb, &read, NULL) ? S_OK : INET_E_DOWNLOAD_FAILURE;
00490     }
00491 
00492     if (pcbRead)
00493         *pcbRead = read;
00494 
00495     if(hres == E_PENDING)
00496         return E_PENDING;
00497     else if(FAILED(hres))
00498         FIXME("Read failed: %08x\n", hres);
00499 
00500     return read ? S_OK : S_FALSE;
00501 }
00502 
00503 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv,
00504                                           ULONG cb, ULONG *pcbWritten)
00505 {
00506     ProtocolStream *This = impl_from_IStream(iface);
00507 
00508     TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten);
00509 
00510     return STG_E_ACCESSDENIED;
00511 }
00512 
00513 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
00514                                          DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
00515 {
00516     ProtocolStream *This = impl_from_IStream(iface);
00517     FIXME("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
00518     return E_NOTIMPL;
00519 }
00520 
00521 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
00522 {
00523     ProtocolStream *This = impl_from_IStream(iface);
00524     FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart);
00525     return E_NOTIMPL;
00526 }
00527 
00528 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm,
00529         ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
00530 {
00531     ProtocolStream *This = impl_from_IStream(iface);
00532     FIXME("(%p)->(%p %d %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten);
00533     return E_NOTIMPL;
00534 }
00535 
00536 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags)
00537 {
00538     ProtocolStream *This = impl_from_IStream(iface);
00539 
00540     TRACE("(%p)->(%08x)\n", This, grfCommitFlags);
00541 
00542     return E_NOTIMPL;
00543 }
00544 
00545 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface)
00546 {
00547     ProtocolStream *This = impl_from_IStream(iface);
00548 
00549     TRACE("(%p)\n", This);
00550 
00551     return E_NOTIMPL;
00552 }
00553 
00554 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
00555                                                ULARGE_INTEGER cb, DWORD dwLockType)
00556 {
00557     ProtocolStream *This = impl_from_IStream(iface);
00558     FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
00559     return E_NOTIMPL;
00560 }
00561 
00562 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface,
00563         ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
00564 {
00565     ProtocolStream *This = impl_from_IStream(iface);
00566     FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
00567     return E_NOTIMPL;
00568 }
00569 
00570 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg,
00571                                          DWORD dwStatFlag)
00572 {
00573     ProtocolStream *This = impl_from_IStream(iface);
00574     TRACE("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag);
00575 
00576     if(!pstatstg)
00577         return E_FAIL;
00578 
00579     memset(pstatstg, 0, sizeof(STATSTG));
00580 
00581     if(!(dwStatFlag&STATFLAG_NONAME) && This->buf->cache_file) {
00582         pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->buf->cache_file)+1)*sizeof(WCHAR));
00583         if(!pstatstg->pwcsName)
00584             return STG_E_INSUFFICIENTMEMORY;
00585 
00586         lstrcpyW(pstatstg->pwcsName, This->buf->cache_file);
00587     }
00588 
00589     pstatstg->type = STGTY_STREAM;
00590     if(This->buf->file != INVALID_HANDLE_VALUE) {
00591         GetFileSizeEx(This->buf->file, (PLARGE_INTEGER)&pstatstg->cbSize);
00592         GetFileTime(This->buf->file, &pstatstg->ctime, &pstatstg->atime, &pstatstg->mtime);
00593         if(pstatstg->cbSize.QuadPart)
00594             pstatstg->grfMode = GENERIC_READ;
00595     }
00596 
00597     return S_OK;
00598 }
00599 
00600 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm)
00601 {
00602     ProtocolStream *This = impl_from_IStream(iface);
00603     FIXME("(%p)->(%p)\n", This, ppstm);
00604     return E_NOTIMPL;
00605 }
00606 
00607 static const IStreamVtbl ProtocolStreamVtbl = {
00608     ProtocolStream_QueryInterface,
00609     ProtocolStream_AddRef,
00610     ProtocolStream_Release,
00611     ProtocolStream_Read,
00612     ProtocolStream_Write,
00613     ProtocolStream_Seek,
00614     ProtocolStream_SetSize,
00615     ProtocolStream_CopyTo,
00616     ProtocolStream_Commit,
00617     ProtocolStream_Revert,
00618     ProtocolStream_LockRegion,
00619     ProtocolStream_UnlockRegion,
00620     ProtocolStream_Stat,
00621     ProtocolStream_Clone
00622 };
00623 
00624 static void stgmed_stream_release(stgmed_obj_t *obj)
00625 {
00626     ProtocolStream *stream = (ProtocolStream*)obj;
00627     IStream_Release(&stream->IStream_iface);
00628 }
00629 
00630 static HRESULT stgmed_stream_fill_stgmed(stgmed_obj_t *obj, STGMEDIUM *stgmed)
00631 {
00632     ProtocolStream *stream = (ProtocolStream*)obj;
00633 
00634     stgmed->tymed = TYMED_ISTREAM;
00635     stgmed->u.pstm = &stream->IStream_iface;
00636     stgmed->pUnkForRelease = &stream->buf->IUnknown_iface;
00637 
00638     return S_OK;
00639 }
00640 
00641 static HRESULT stgmed_stream_get_result(stgmed_obj_t *obj, DWORD bindf, void **result)
00642 {
00643     ProtocolStream *stream = (ProtocolStream*)obj;
00644 
00645     if(!(bindf & BINDF_ASYNCHRONOUS) && stream->buf->file == INVALID_HANDLE_VALUE
00646        && stream->buf->hres != S_FALSE)
00647         return INET_E_DATA_NOT_AVAILABLE;
00648 
00649     IStream_AddRef(&stream->IStream_iface);
00650     *result = &stream->IStream_iface;
00651     return S_OK;
00652 }
00653 
00654 static const stgmed_obj_vtbl stgmed_stream_vtbl = {
00655     stgmed_stream_release,
00656     stgmed_stream_fill_stgmed,
00657     stgmed_stream_get_result
00658 };
00659 
00660 typedef struct {
00661     stgmed_obj_t stgmed_obj;
00662     stgmed_buf_t *buf;
00663 } stgmed_file_obj_t;
00664 
00665 static stgmed_obj_t *create_stgmed_stream(stgmed_buf_t *buf)
00666 {
00667     ProtocolStream *ret = heap_alloc(sizeof(ProtocolStream));
00668 
00669     ret->stgmed_obj.vtbl = &stgmed_stream_vtbl;
00670     ret->IStream_iface.lpVtbl = &ProtocolStreamVtbl;
00671     ret->ref = 1;
00672 
00673     IUnknown_AddRef(&buf->IUnknown_iface);
00674     ret->buf = buf;
00675 
00676     URLMON_LockModule();
00677 
00678     return &ret->stgmed_obj;
00679 }
00680 
00681 static void stgmed_file_release(stgmed_obj_t *obj)
00682 {
00683     stgmed_file_obj_t *file_obj = (stgmed_file_obj_t*)obj;
00684 
00685     IUnknown_Release(&file_obj->buf->IUnknown_iface);
00686     heap_free(file_obj);
00687 }
00688 
00689 static HRESULT stgmed_file_fill_stgmed(stgmed_obj_t *obj, STGMEDIUM *stgmed)
00690 {
00691     stgmed_file_obj_t *file_obj = (stgmed_file_obj_t*)obj;
00692 
00693     if(!file_obj->buf->cache_file) {
00694         WARN("cache_file not set\n");
00695         return INET_E_DATA_NOT_AVAILABLE;
00696     }
00697 
00698     read_protocol_data(file_obj->buf);
00699 
00700     stgmed->tymed = TYMED_FILE;
00701     stgmed->u.lpszFileName = file_obj->buf->cache_file;
00702     stgmed->pUnkForRelease = &file_obj->buf->IUnknown_iface;
00703 
00704     return S_OK;
00705 }
00706 
00707 static HRESULT stgmed_file_get_result(stgmed_obj_t *obj, DWORD bindf, void **result)
00708 {
00709     return bindf & BINDF_ASYNCHRONOUS ? MK_S_ASYNCHRONOUS : S_OK;
00710 }
00711 
00712 static const stgmed_obj_vtbl stgmed_file_vtbl = {
00713     stgmed_file_release,
00714     stgmed_file_fill_stgmed,
00715     stgmed_file_get_result
00716 };
00717 
00718 static stgmed_obj_t *create_stgmed_file(stgmed_buf_t *buf)
00719 {
00720     stgmed_file_obj_t *ret = heap_alloc(sizeof(*ret));
00721 
00722     ret->stgmed_obj.vtbl = &stgmed_file_vtbl;
00723 
00724     IUnknown_AddRef(&buf->IUnknown_iface);
00725     ret->buf = buf;
00726 
00727     return &ret->stgmed_obj;
00728 }
00729 
00730 static inline Binding *impl_from_IBinding(IBinding *iface)
00731 {
00732     return CONTAINING_RECORD(iface, Binding, IBinding_iface);
00733 }
00734 
00735 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
00736 {
00737     Binding *This = impl_from_IBinding(iface);
00738 
00739     *ppv = NULL;
00740 
00741     if(IsEqualGUID(&IID_IUnknown, riid)) {
00742         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
00743         *ppv = &This->IBinding_iface;
00744     }else if(IsEqualGUID(&IID_IBinding, riid)) {
00745         TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
00746         *ppv = &This->IBinding_iface;
00747     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
00748         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
00749         *ppv = &This->IInternetProtocolSink_iface;
00750     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
00751         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
00752         *ppv = &This->IInternetBindInfo_iface;
00753     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
00754         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
00755         *ppv = &This->IServiceProvider_iface;
00756     }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
00757         TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
00758 
00759         /* NOTE: This violidates COM rules, but tests prove that we should do it */
00760         if(!This->protocol->wininet_info)
00761            return E_NOINTERFACE;
00762 
00763         *ppv = &This->IWinInetHttpInfo_iface;
00764     }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
00765         TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
00766 
00767         if(!This->protocol->wininet_http_info)
00768             return E_NOINTERFACE;
00769 
00770         *ppv = &This->IWinInetHttpInfo_iface;
00771     }
00772 
00773     if(*ppv) {
00774         IBinding_AddRef(&This->IBinding_iface);
00775         return S_OK;
00776     }
00777 
00778     WARN("Unsupported interface %s\n", debugstr_guid(riid));
00779     return E_NOINTERFACE;
00780 }
00781 
00782 static ULONG WINAPI Binding_AddRef(IBinding *iface)
00783 {
00784     Binding *This = impl_from_IBinding(iface);
00785     LONG ref = InterlockedIncrement(&This->ref);
00786 
00787     TRACE("(%p) ref=%d\n", This, ref);
00788 
00789     return ref;
00790 }
00791 
00792 static ULONG WINAPI Binding_Release(IBinding *iface)
00793 {
00794     Binding *This = impl_from_IBinding(iface);
00795     LONG ref = InterlockedDecrement(&This->ref);
00796 
00797     TRACE("(%p) ref=%d\n", This, ref);
00798 
00799     if(!ref) {
00800         if(This->notif_hwnd)
00801             release_notif_hwnd(This->notif_hwnd);
00802         if(This->mon)
00803             IMoniker_Release(This->mon);
00804         if(This->callback)
00805             IBindStatusCallback_Release(This->callback);
00806         if(This->protocol)
00807             IInternetProtocolEx_Release(&This->protocol->IInternetProtocolEx_iface);
00808         if(This->service_provider)
00809             IServiceProvider_Release(This->service_provider);
00810         if(This->stgmed_buf)
00811             IUnknown_Release(&This->stgmed_buf->IUnknown_iface);
00812         if(This->stgmed_obj)
00813             This->stgmed_obj->vtbl->release(This->stgmed_obj);
00814         if(This->obj)
00815             IUnknown_Release(This->obj);
00816         if(This->bctx)
00817             IBindCtx_Release(This->bctx);
00818 
00819         ReleaseBindInfo(&This->bindinfo);
00820         This->section.DebugInfo->Spare[0] = 0;
00821         DeleteCriticalSection(&This->section);
00822         SysFreeString(This->url);
00823         heap_free(This->mime);
00824         heap_free(This->redirect_url);
00825         heap_free(This);
00826 
00827         URLMON_UnlockModule();
00828     }
00829 
00830     return ref;
00831 }
00832 
00833 static HRESULT WINAPI Binding_Abort(IBinding *iface)
00834 {
00835     Binding *This = impl_from_IBinding(iface);
00836     HRESULT hres;
00837 
00838     TRACE("(%p)\n", This);
00839 
00840     if(This->state & BINDING_ABORTED)
00841         return E_FAIL;
00842 
00843     hres = IInternetProtocolEx_Abort(&This->protocol->IInternetProtocolEx_iface, E_ABORT,
00844             ERROR_SUCCESS);
00845     if(FAILED(hres))
00846         return hres;
00847 
00848     This->state |= BINDING_ABORTED;
00849     return S_OK;
00850 }
00851 
00852 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
00853 {
00854     Binding *This = impl_from_IBinding(iface);
00855     FIXME("(%p)\n", This);
00856     return E_NOTIMPL;
00857 }
00858 
00859 static HRESULT WINAPI Binding_Resume(IBinding *iface)
00860 {
00861     Binding *This = impl_from_IBinding(iface);
00862     FIXME("(%p)\n", This);
00863     return E_NOTIMPL;
00864 }
00865 
00866 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
00867 {
00868     Binding *This = impl_from_IBinding(iface);
00869     FIXME("(%p)->(%d)\n", This, nPriority);
00870     return E_NOTIMPL;
00871 }
00872 
00873 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
00874 {
00875     Binding *This = impl_from_IBinding(iface);
00876     FIXME("(%p)->(%p)\n", This, pnPriority);
00877     return E_NOTIMPL;
00878 }
00879 
00880 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
00881         DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
00882 {
00883     Binding *This = impl_from_IBinding(iface);
00884     FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
00885     return E_NOTIMPL;
00886 }
00887 
00888 static const IBindingVtbl BindingVtbl = {
00889     Binding_QueryInterface,
00890     Binding_AddRef,
00891     Binding_Release,
00892     Binding_Abort,
00893     Binding_Suspend,
00894     Binding_Resume,
00895     Binding_SetPriority,
00896     Binding_GetPriority,
00897     Binding_GetBindResult
00898 };
00899 
00900 static Binding *get_bctx_binding(IBindCtx *bctx)
00901 {
00902     IBinding *binding;
00903     IUnknown *unk;
00904     HRESULT hres;
00905 
00906     hres = IBindCtx_GetObjectParam(bctx, cbinding_contextW, &unk);
00907     if(FAILED(hres))
00908         return NULL;
00909 
00910     hres = IUnknown_QueryInterface(unk, &IID_IBinding, (void**)&binding);
00911     IUnknown_Release(unk);
00912     if(FAILED(hres))
00913         return NULL;
00914 
00915     if (binding->lpVtbl != &BindingVtbl)
00916         return NULL;
00917     return impl_from_IBinding(binding);
00918 }
00919 
00920 static inline Binding *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
00921 {
00922     return CONTAINING_RECORD(iface, Binding, IInternetProtocolSink_iface);
00923 }
00924 
00925 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
00926         REFIID riid, void **ppv)
00927 {
00928     Binding *This = impl_from_IInternetProtocolSink(iface);
00929     return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv);
00930 }
00931 
00932 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
00933 {
00934     Binding *This = impl_from_IInternetProtocolSink(iface);
00935     return IBinding_AddRef(&This->IBinding_iface);
00936 }
00937 
00938 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
00939 {
00940     Binding *This = impl_from_IInternetProtocolSink(iface);
00941     return IBinding_Release(&This->IBinding_iface);
00942 }
00943 
00944 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
00945         PROTOCOLDATA *pProtocolData)
00946 {
00947     Binding *This = impl_from_IInternetProtocolSink(iface);
00948 
00949     WARN("(%p)->(%p)\n", This, pProtocolData);
00950 
00951     return E_FAIL;
00952 }
00953 
00954 static void on_progress(Binding *This, ULONG progress, ULONG progress_max,
00955                         ULONG status_code, LPCWSTR status_text)
00956 {
00957     IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
00958             status_code, status_text);
00959 }
00960 
00961 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
00962         ULONG ulStatusCode, LPCWSTR szStatusText)
00963 {
00964     Binding *This = impl_from_IInternetProtocolSink(iface);
00965 
00966     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
00967 
00968     switch(ulStatusCode) {
00969     case BINDSTATUS_FINDINGRESOURCE:
00970         on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText);
00971         break;
00972     case BINDSTATUS_CONNECTING:
00973         on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText);
00974         break;
00975     case BINDSTATUS_REDIRECTING:
00976         heap_free(This->redirect_url);
00977         This->redirect_url = heap_strdupW(szStatusText);
00978         on_progress(This, 0, 0, BINDSTATUS_REDIRECTING, szStatusText);
00979         break;
00980     case BINDSTATUS_BEGINDOWNLOADDATA:
00981         break;
00982     case BINDSTATUS_SENDINGREQUEST:
00983         on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText);
00984         break;
00985     case BINDSTATUS_PROTOCOLCLASSID:
00986         break;
00987     case BINDSTATUS_MIMETYPEAVAILABLE:
00988     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
00989         mime_available(This, szStatusText);
00990         break;
00991     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
00992         cache_file_available(This, szStatusText);
00993         break;
00994     case BINDSTATUS_DECODING:
00995         IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_DECODING, szStatusText);
00996         break;
00997     case BINDSTATUS_LOADINGMIMEHANDLER:
00998         on_progress(This, 0, 0, BINDSTATUS_LOADINGMIMEHANDLER, szStatusText);
00999         break;
01000     case BINDSTATUS_DIRECTBIND: /* FIXME: Handle BINDSTATUS_DIRECTBIND in BindProtocol */
01001         This->report_mime = FALSE;
01002         break;
01003     case BINDSTATUS_ACCEPTRANGES:
01004         break;
01005     default:
01006         FIXME("Unhandled status code %d\n", ulStatusCode);
01007         return E_NOTIMPL;
01008     };
01009 
01010     return S_OK;
01011 }
01012 
01013 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max)
01014 {
01015     FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM};
01016     BOOL sent_begindownloaddata = FALSE;
01017 
01018     TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max);
01019 
01020     if(This->download_state == END_DOWNLOAD || (This->state & BINDING_ABORTED)) {
01021         read_protocol_data(This->stgmed_buf);
01022         return;
01023     }
01024 
01025     if(This->state & BINDING_STOPPED)
01026         return;
01027 
01028     if(This->stgmed_buf->file != INVALID_HANDLE_VALUE)
01029         read_protocol_data(This->stgmed_buf);
01030 
01031     if(This->download_state == BEFORE_DOWNLOAD) {
01032         This->download_state = DOWNLOADING;
01033         sent_begindownloaddata = TRUE;
01034         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
01035                 BINDSTATUS_BEGINDOWNLOADDATA, This->url);
01036 
01037         if(This->stgmed_buf->cache_file)
01038             IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
01039                     BINDSTATUS_CACHEFILENAMEAVAILABLE, This->stgmed_buf->cache_file);
01040     }
01041 
01042     if(This->stgmed_buf->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) {
01043         This->download_state = END_DOWNLOAD;
01044         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
01045                 BINDSTATUS_ENDDOWNLOADDATA, This->url);
01046     }else if(!sent_begindownloaddata) {
01047         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
01048                 BINDSTATUS_DOWNLOADINGDATA, This->url);
01049     }
01050 
01051     if(This->state & (BINDING_STOPPED|BINDING_ABORTED))
01052         return;
01053 
01054     if(This->to_object) {
01055         if(!(This->state & BINDING_OBJAVAIL)) {
01056             IBinding_AddRef(&This->IBinding_iface);
01057             create_object(This);
01058             IBinding_Release(&This->IBinding_iface);
01059         }
01060     }else {
01061         STGMEDIUM stgmed;
01062         HRESULT hres;
01063 
01064         if(!(This->state & BINDING_LOCKED)) {
01065             HRESULT hres = IInternetProtocolEx_LockRequest(
01066                     &This->protocol->IInternetProtocolEx_iface, 0);
01067             if(SUCCEEDED(hres))
01068                 This->state |= BINDING_LOCKED;
01069         }
01070 
01071         hres = This->stgmed_obj->vtbl->fill_stgmed(This->stgmed_obj, &stgmed);
01072         if(FAILED(hres)) {
01073             stop_binding(This, hres, NULL);
01074             return;
01075         }
01076 
01077         formatetc.tymed = stgmed.tymed;
01078         formatetc.cfFormat = This->clipboard_format;
01079 
01080         IBindStatusCallback_OnDataAvailable(This->callback, bscf, progress,
01081                 &formatetc, &stgmed);
01082 
01083         if(This->download_state == END_DOWNLOAD)
01084             stop_binding(This, S_OK, NULL);
01085     }
01086 }
01087 
01088 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
01089         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
01090 {
01091     Binding *This = impl_from_IInternetProtocolSink(iface);
01092 
01093     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
01094 
01095     report_data(This, grfBSCF, ulProgress, ulProgressMax);
01096     return S_OK;
01097 }
01098 
01099 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
01100         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
01101 {
01102     Binding *This = impl_from_IInternetProtocolSink(iface);
01103 
01104     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
01105 
01106     stop_binding(This, hrResult, szResult);
01107     IInternetProtocolEx_Terminate(&This->protocol->IInternetProtocolEx_iface, 0);
01108     return S_OK;
01109 }
01110 
01111 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
01112     InternetProtocolSink_QueryInterface,
01113     InternetProtocolSink_AddRef,
01114     InternetProtocolSink_Release,
01115     InternetProtocolSink_Switch,
01116     InternetProtocolSink_ReportProgress,
01117     InternetProtocolSink_ReportData,
01118     InternetProtocolSink_ReportResult
01119 };
01120 
01121 static inline Binding *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
01122 {
01123     return CONTAINING_RECORD(iface, Binding, IInternetBindInfo_iface);
01124 }
01125 
01126 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
01127         REFIID riid, void **ppv)
01128 {
01129     Binding *This = impl_from_IInternetBindInfo(iface);
01130     return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv);
01131 }
01132 
01133 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
01134 {
01135     Binding *This = impl_from_IInternetBindInfo(iface);
01136     return IBinding_AddRef(&This->IBinding_iface);
01137 }
01138 
01139 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
01140 {
01141     Binding *This = impl_from_IInternetBindInfo(iface);
01142     return IBinding_Release(&This->IBinding_iface);
01143 }
01144 
01145 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
01146         DWORD *grfBINDF, BINDINFO *pbindinfo)
01147 {
01148     Binding *This = impl_from_IInternetBindInfo(iface);
01149 
01150     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
01151 
01152     *grfBINDF = This->bindf;
01153 
01154     *pbindinfo = This->bindinfo;
01155 
01156     if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
01157         FIXME("copy strings\n");
01158 
01159     if(pbindinfo->stgmedData.pUnkForRelease)
01160         IUnknown_AddRef(pbindinfo->stgmedData.pUnkForRelease);
01161 
01162     if(pbindinfo->pUnk)
01163         IUnknown_AddRef(pbindinfo->pUnk);
01164 
01165     return S_OK;
01166 }
01167 
01168 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
01169         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
01170 {
01171     Binding *This = impl_from_IInternetBindInfo(iface);
01172 
01173     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
01174 
01175     switch(ulStringType) {
01176     case BINDSTRING_ACCEPT_MIMES: {
01177         static const WCHAR wszMimes[] = {'*','/','*',0};
01178 
01179         if(!ppwzStr || !pcElFetched)
01180             return E_INVALIDARG;
01181 
01182         ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
01183         memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
01184         *pcElFetched = 1;
01185         return S_OK;
01186     }
01187     case BINDSTRING_USER_AGENT: {
01188         IInternetBindInfo *bindinfo = NULL;
01189         HRESULT hres;
01190 
01191         hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
01192                                                   (void**)&bindinfo);
01193         if(FAILED(hres))
01194             return hres;
01195 
01196         hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
01197                                                cEl, pcElFetched);
01198         IInternetBindInfo_Release(bindinfo);
01199 
01200         return hres;
01201     }
01202     case BINDSTRING_URL: {
01203         DWORD size = (SysStringLen(This->url)+1) * sizeof(WCHAR);
01204 
01205         if(!ppwzStr || !pcElFetched)
01206             return E_INVALIDARG;
01207 
01208         *ppwzStr = CoTaskMemAlloc(size);
01209         memcpy(*ppwzStr, This->url, size);
01210         *pcElFetched = 1;
01211         return S_OK;
01212     }
01213     }
01214 
01215     FIXME("not supported string type %d\n", ulStringType);
01216     return E_NOTIMPL;
01217 }
01218 
01219 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
01220     InternetBindInfo_QueryInterface,
01221     InternetBindInfo_AddRef,
01222     InternetBindInfo_Release,
01223     InternetBindInfo_GetBindInfo,
01224     InternetBindInfo_GetBindString
01225 };
01226 
01227 static inline Binding *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
01228 {
01229     return CONTAINING_RECORD(iface, Binding, IWinInetHttpInfo_iface);
01230 }
01231 
01232 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
01233 {
01234     Binding *This = impl_from_IWinInetHttpInfo(iface);
01235     return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv);
01236 }
01237 
01238 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
01239 {
01240     Binding *This = impl_from_IWinInetHttpInfo(iface);
01241     return IBinding_AddRef(&This->IBinding_iface);
01242 }
01243 
01244 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
01245 {
01246     Binding *This = impl_from_IWinInetHttpInfo(iface);
01247     return IBinding_Release(&This->IBinding_iface);
01248 }
01249 
01250 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
01251         void *pBuffer, DWORD *pcbBuffer)
01252 {
01253     Binding *This = impl_from_IWinInetHttpInfo(iface);
01254     TRACE("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
01255 
01256     if(!This->protocol->wininet_info)
01257         return E_FAIL;
01258 
01259     return IWinInetInfo_QueryOption(This->protocol->wininet_info,
01260             dwOption, pBuffer, pcbBuffer);
01261 }
01262 
01263 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
01264         void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
01265 {
01266     Binding *This = impl_from_IWinInetHttpInfo(iface);
01267     TRACE("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
01268 
01269     if(!This->protocol->wininet_http_info)
01270         return E_FAIL;
01271 
01272     return IWinInetHttpInfo_QueryInfo(This->protocol->wininet_http_info,
01273             dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
01274 }
01275 
01276 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
01277     WinInetHttpInfo_QueryInterface,
01278     WinInetHttpInfo_AddRef,
01279     WinInetHttpInfo_Release,
01280     WinInetHttpInfo_QueryOption,
01281     WinInetHttpInfo_QueryInfo
01282 };
01283 
01284 static inline Binding *impl_from_IServiceProvider(IServiceProvider *iface)
01285 {
01286     return CONTAINING_RECORD(iface, Binding, IServiceProvider_iface);
01287 }
01288 
01289 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
01290         REFIID riid, void **ppv)
01291 {
01292     Binding *This = impl_from_IServiceProvider(iface);
01293     return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv);
01294 }
01295 
01296 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
01297 {
01298     Binding *This = impl_from_IServiceProvider(iface);
01299     return IBinding_AddRef(&This->IBinding_iface);
01300 }
01301 
01302 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
01303 {
01304     Binding *This = impl_from_IServiceProvider(iface);
01305     return IBinding_Release(&This->IBinding_iface);
01306 }
01307 
01308 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
01309         REFGUID guidService, REFIID riid, void **ppv)
01310 {
01311     Binding *This = impl_from_IServiceProvider(iface);
01312     HRESULT hres;
01313 
01314     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
01315 
01316     if(This->service_provider) {
01317         hres = IServiceProvider_QueryService(This->service_provider, guidService,
01318                                              riid, ppv);
01319         if(SUCCEEDED(hres))
01320             return hres;
01321     }
01322 
01323     WARN("unknown service %s\n", debugstr_guid(guidService));
01324     return E_NOINTERFACE;
01325 }
01326 
01327 static const IServiceProviderVtbl ServiceProviderVtbl = {
01328     ServiceProvider_QueryInterface,
01329     ServiceProvider_AddRef,
01330     ServiceProvider_Release,
01331     ServiceProvider_QueryService
01332 };
01333 
01334 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
01335 {
01336     IUnknown *unk;
01337     HRESULT hres;
01338 
01339     hres = IBindCtx_GetObjectParam(pbc, bscb_holderW, &unk);
01340     if(FAILED(hres))
01341         return create_default_callback(callback);
01342 
01343     hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)callback);
01344     IUnknown_Release(unk);
01345     return hres;
01346 }
01347 
01348 static BOOL is_urlmon_protocol(IUri *uri)
01349 {
01350     DWORD scheme;
01351     HRESULT hres;
01352 
01353     hres = IUri_GetScheme(uri, &scheme);
01354     if(FAILED(hres))
01355         return FALSE;
01356 
01357     switch(scheme) {
01358     case URL_SCHEME_FILE:
01359     case URL_SCHEME_FTP:
01360     case URL_SCHEME_GOPHER:
01361     case URL_SCHEME_HTTP:
01362     case URL_SCHEME_HTTPS:
01363     case URL_SCHEME_MK:
01364         return TRUE;
01365     }
01366 
01367     return FALSE;
01368 }
01369 
01370 static HRESULT Binding_Create(IMoniker *mon, Binding *binding_ctx, IUri *uri, IBindCtx *pbc,
01371         BOOL to_obj, REFIID riid, Binding **binding)
01372 {
01373     Binding *ret;
01374     HRESULT hres;
01375 
01376     URLMON_LockModule();
01377 
01378     ret = heap_alloc_zero(sizeof(Binding));
01379 
01380     ret->IBinding_iface.lpVtbl = &BindingVtbl;
01381     ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
01382     ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
01383     ret->IWinInetHttpInfo_iface.lpVtbl = &WinInetHttpInfoVtbl;
01384     ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
01385 
01386     ret->ref = 1;
01387 
01388     ret->to_object = to_obj;
01389     ret->iid = *riid;
01390     ret->notif_hwnd = get_notif_hwnd();
01391     ret->report_mime = !binding_ctx;
01392     ret->download_state = BEFORE_DOWNLOAD;
01393 
01394     if(to_obj) {
01395         IBindCtx_AddRef(pbc);
01396         ret->bctx = pbc;
01397     }
01398 
01399     if(mon) {
01400         IMoniker_AddRef(mon);
01401         ret->mon = mon;
01402     }
01403 
01404     ret->bindinfo.cbSize = sizeof(BINDINFO);
01405 
01406     InitializeCriticalSection(&ret->section);
01407     ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section");
01408 
01409     hres = get_callback(pbc, &ret->callback);
01410     if(FAILED(hres)) {
01411         WARN("Could not get IBindStatusCallback\n");
01412         IBinding_Release(&ret->IBinding_iface);
01413         return hres;
01414     }
01415 
01416     IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
01417                                        (void**)&ret->service_provider);
01418 
01419     if(binding_ctx) {
01420         ret->protocol = binding_ctx->protocol;
01421         IInternetProtocolEx_AddRef(&ret->protocol->IInternetProtocolEx_iface);
01422     }else {
01423         hres = create_binding_protocol(TRUE, &ret->protocol);
01424         if(FAILED(hres)) {
01425             WARN("Could not get protocol handler\n");
01426             IBinding_Release(&ret->IBinding_iface);
01427             return hres;
01428         }
01429     }
01430 
01431     hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
01432     if(FAILED(hres)) {
01433         WARN("GetBindInfo failed: %08x\n", hres);
01434         IBinding_Release(&ret->IBinding_iface);
01435         return hres;
01436     }
01437 
01438     TRACE("bindf %08x\n", ret->bindf);
01439     dump_BINDINFO(&ret->bindinfo);
01440 
01441     ret->bindf |= BINDF_FROMURLMON;
01442     if(to_obj)
01443         ret->bindinfo.dwOptions |= 0x100000;
01444 
01445     if(!(ret->bindf & BINDF_ASYNCHRONOUS) || !(ret->bindf & BINDF_PULLDATA)) {
01446         ret->bindf |= BINDF_NEEDFILE;
01447         ret->use_cache_file = TRUE;
01448     }else if(!is_urlmon_protocol(uri)) {
01449         ret->bindf |= BINDF_NEEDFILE;
01450     }
01451 
01452     hres = IUri_GetDisplayUri(uri, &ret->url);
01453     if(FAILED(hres)) {
01454         IBinding_Release(&ret->IBinding_iface);
01455         return hres;
01456     }
01457 
01458     if(binding_ctx) {
01459         ret->stgmed_buf = binding_ctx->stgmed_buf;
01460         IUnknown_AddRef(&ret->stgmed_buf->IUnknown_iface);
01461         ret->clipboard_format = binding_ctx->clipboard_format;
01462     }else {
01463         ret->stgmed_buf = create_stgmed_buf(&ret->protocol->IInternetProtocolEx_iface);
01464     }
01465 
01466     if(to_obj) {
01467         ret->stgmed_obj = NULL;
01468     }else if(IsEqualGUID(&IID_IStream, riid)) {
01469         ret->stgmed_obj = create_stgmed_stream(ret->stgmed_buf);
01470     }else if(IsEqualGUID(&IID_IUnknown, riid)) {
01471         ret->bindf |= BINDF_NEEDFILE;
01472         ret->stgmed_obj = create_stgmed_file(ret->stgmed_buf);
01473     }else {
01474         FIXME("Unsupported riid %s\n", debugstr_guid(riid));
01475         IBinding_Release(&ret->IBinding_iface);
01476         return E_NOTIMPL;
01477     }
01478 
01479     *binding = ret;
01480     return S_OK;
01481 }
01482 
01483 static HRESULT start_binding(IMoniker *mon, Binding *binding_ctx, IUri *uri, IBindCtx *pbc,
01484                              BOOL to_obj, REFIID riid, Binding **ret)
01485 {
01486     Binding *binding = NULL;
01487     HRESULT hres;
01488     MSG msg;
01489 
01490     hres = Binding_Create(mon, binding_ctx, uri, pbc, to_obj, riid, &binding);
01491     if(FAILED(hres))
01492         return hres;
01493 
01494     hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, &binding->IBinding_iface);
01495     if(FAILED(hres)) {
01496         WARN("OnStartBinding failed: %08x\n", hres);
01497         if(hres != E_ABORT && hres != E_NOTIMPL)
01498             hres = INET_E_DOWNLOAD_FAILURE;
01499 
01500         stop_binding(binding, hres, NULL);
01501         IBinding_Release(&binding->IBinding_iface);
01502         return hres;
01503     }
01504 
01505     if(binding_ctx) {
01506         set_binding_sink(binding->protocol, &binding->IInternetProtocolSink_iface,
01507                 &binding->IInternetBindInfo_iface);
01508         if(binding_ctx->redirect_url)
01509             IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_REDIRECTING, binding_ctx->redirect_url);
01510         report_data(binding, BSCF_FIRSTDATANOTIFICATION | (binding_ctx->download_state == END_DOWNLOAD ? BSCF_LASTDATANOTIFICATION : 0),
01511                 0, 0);
01512     }else {
01513         hres = IInternetProtocolEx_StartEx(&binding->protocol->IInternetProtocolEx_iface, uri,
01514                 &binding->IInternetProtocolSink_iface, &binding->IInternetBindInfo_iface,
01515                 PI_APARTMENTTHREADED|PI_MIMEVERIFICATION, 0);
01516 
01517         TRACE("start ret %08x\n", hres);
01518 
01519         if(FAILED(hres) && hres != E_PENDING) {
01520             stop_binding(binding, hres, NULL);
01521             IBinding_Release(&binding->IBinding_iface);
01522 
01523             return hres;
01524         }
01525     }
01526 
01527     while(!(binding->bindf & BINDF_ASYNCHRONOUS) &&
01528           !(binding->state & BINDING_STOPPED)) {
01529         MsgWaitForMultipleObjects(0, NULL, FALSE, 5000, QS_POSTMESSAGE);
01530         while (PeekMessageW(&msg, binding->notif_hwnd, WM_USER, WM_USER+117, PM_REMOVE|PM_NOYIELD)) {
01531             TranslateMessage(&msg);
01532             DispatchMessageW(&msg);
01533         }
01534     }
01535 
01536     *ret = binding;
01537     return S_OK;
01538 }
01539 
01540 HRESULT bind_to_storage(IUri *uri, IBindCtx *pbc, REFIID riid, void **ppv)
01541 {
01542     Binding *binding = NULL, *binding_ctx;
01543     HRESULT hres;
01544 
01545     binding_ctx = get_bctx_binding(pbc);
01546 
01547     hres = start_binding(NULL, binding_ctx, uri, pbc, FALSE, riid, &binding);
01548     if(binding_ctx)
01549         IBinding_Release(&binding_ctx->IBinding_iface);
01550     if(FAILED(hres))
01551         return hres;
01552 
01553     if(binding->hres == S_OK && binding->download_state != BEFORE_DOWNLOAD /* FIXME */) {
01554         if((binding->state & BINDING_STOPPED) && (binding->state & BINDING_LOCKED))
01555             IInternetProtocolEx_UnlockRequest(&binding->protocol->IInternetProtocolEx_iface);
01556 
01557         hres = binding->stgmed_obj->vtbl->get_result(binding->stgmed_obj, binding->bindf, ppv);
01558     }else if(binding->bindf & BINDF_ASYNCHRONOUS) {
01559         hres = MK_S_ASYNCHRONOUS;
01560     }else {
01561         hres = FAILED(binding->hres) ? binding->hres : S_OK;
01562     }
01563 
01564     IBinding_Release(&binding->IBinding_iface);
01565 
01566     return hres;
01567 }
01568 
01569 HRESULT bind_to_object(IMoniker *mon, IUri *uri, IBindCtx *pbc, REFIID riid, void **ppv)
01570 {
01571     Binding *binding;
01572     HRESULT hres;
01573 
01574     *ppv = NULL;
01575 
01576     hres = start_binding(mon, NULL, uri, pbc, TRUE, riid, &binding);
01577     if(FAILED(hres))
01578         return hres;
01579 
01580     if(binding->hres != S_OK) {
01581         hres = SUCCEEDED(binding->hres) ? S_OK : binding->hres;
01582     }else if(binding->bindf & BINDF_ASYNCHRONOUS) {
01583         hres = MK_S_ASYNCHRONOUS;
01584     }else {
01585         *ppv = binding->obj;
01586         IUnknown_AddRef(binding->obj);
01587         hres = S_OK;
01588     }
01589 
01590     IBinding_Release(&binding->IBinding_iface);
01591 
01592     return hres;
01593 }

Generated on Fri May 25 2012 04:24:44 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.