| /* | |
| * UrlMon | |
| * | |
| * Copyright 1999 Ulrich Czekalla for Corel Corporation | |
| * Copyright 2002 Huw D M Davies for CodeWeavers | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #define COM_NO_WINDOWS_H | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #define COBJMACROS | |
| #define NONAMELESSUNION | |
| #define NONAMELESSSTRUCT | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winreg.h" | |
| #include "winternl.h" | |
| #include "winuser.h" | |
| #include "objbase.h" | |
| #include "wine/debug.h" | |
| #include "wine/unicode.h" | |
| #include "ole2.h" | |
| #include "urlmon.h" | |
| #include "wininet.h" | |
| #include "shlwapi.h" | |
| #include "urlmon_main.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(urlmon); | |
| /* native urlmon.dll uses this key, too */ | |
| static const WCHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 }; | |
| /*static BOOL registered_wndclass = FALSE;*/ | |
| /* filemoniker data structure */ | |
| typedef struct URLMonikerImpl{ | |
| IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/ | |
| IBindingVtbl* lpvtbl2; /* VTable to IBinding interface */ | |
| ULONG ref; /* reference counter for this object */ | |
| LPOLESTR URLName; /* URL string identified by this URLmoniker */ | |
| HWND hwndCallback; | |
| IBindCtx *pBC; | |
| HINTERNET hinternet, hconnect, hrequest; | |
| } URLMonikerImpl; | |
| /******************************************************************************* | |
| * URLMoniker_QueryInterface | |
| *******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); | |
| /* Perform a sanity check on the parameters.*/ | |
| if ( (This==0) || (ppvObject==0) ) | |
| return E_INVALIDARG; | |
| /* Initialize the return parameter */ | |
| *ppvObject = 0; | |
| /* Compare the riid with the interface IDs implemented by this object.*/ | |
| if (IsEqualIID(&IID_IUnknown, riid) || | |
| IsEqualIID(&IID_IPersist, riid) || | |
| IsEqualIID(&IID_IPersistStream,riid) || | |
| IsEqualIID(&IID_IMoniker, riid) | |
| ) | |
| *ppvObject = iface; | |
| /* Check that we obtained an interface.*/ | |
| if ((*ppvObject)==0) | |
| return E_NOINTERFACE; | |
| /* Query Interface always increases the reference count by one when it is successful */ | |
| IMoniker_AddRef(iface); | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_AddRef | |
| ******************************************************************************/ | |
| static ULONG WINAPI URLMonikerImpl_AddRef(IMoniker* iface) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| ULONG refCount = InterlockedIncrement(&This->ref); | |
| TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); | |
| URLMON_LockModule(); | |
| return refCount; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_Release | |
| ******************************************************************************/ | |
| static ULONG WINAPI URLMonikerImpl_Release(IMoniker* iface) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| ULONG refCount = InterlockedDecrement(&This->ref); | |
| TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); | |
| /* destroy the object if there's no more reference on it */ | |
| if (!refCount) { | |
| HeapFree(GetProcessHeap(),0,This->URLName); | |
| HeapFree(GetProcessHeap(),0,This); | |
| } | |
| URLMON_UnlockModule(); | |
| return refCount; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_GetClassID | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_GetClassID(IMoniker* iface, | |
| CLSID *pClassID)/* Pointer to CLSID of object */ | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| TRACE("(%p,%p)\n",This,pClassID); | |
| if (pClassID==NULL) | |
| return E_POINTER; | |
| /* Windows always returns CLSID_StdURLMoniker */ | |
| *pClassID = CLSID_StdURLMoniker; | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_IsDirty | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_IsDirty(IMoniker* iface) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| /* Note that the OLE-provided implementations of the IPersistStream::IsDirty | |
| method in the OLE-provided moniker interfaces always return S_FALSE because | |
| their internal state never changes. */ | |
| TRACE("(%p)\n",This); | |
| return S_FALSE; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_Load | |
| * | |
| * NOTE | |
| * Writes a ULONG containing length of unicode string, followed | |
| * by that many unicode characters | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_Load(IMoniker* iface,IStream* pStm) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| HRESULT res; | |
| ULONG len; | |
| ULONG got; | |
| TRACE("(%p,%p)\n",This,pStm); | |
| if(!pStm) | |
| return E_INVALIDARG; | |
| res = IStream_Read(pStm, &len, sizeof(ULONG), &got); | |
| if(SUCCEEDED(res)) { | |
| if(got == sizeof(ULONG)) { | |
| HeapFree(GetProcessHeap(), 0, This->URLName); | |
| This->URLName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(len+1)); | |
| if(!This->URLName) | |
| res = E_OUTOFMEMORY; | |
| else { | |
| res = IStream_Read(pStm, This->URLName, len, NULL); | |
| This->URLName[len] = 0; | |
| } | |
| } | |
| else | |
| res = E_FAIL; | |
| } | |
| return res; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_Save | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_Save(IMoniker* iface, | |
| IStream* pStm,/* pointer to the stream where the object is to be saved */ | |
| BOOL fClearDirty)/* Specifies whether to clear the dirty flag */ | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| HRESULT res; | |
| ULONG len; | |
| TRACE("(%p,%p,%d)\n",This,pStm,fClearDirty); | |
| if(!pStm) | |
| return E_INVALIDARG; | |
| len = strlenW(This->URLName); | |
| res=IStream_Write(pStm,&len,sizeof(ULONG),NULL); | |
| if(SUCCEEDED(res)) | |
| res=IStream_Write(pStm,&This->URLName,len*sizeof(WCHAR),NULL); | |
| return res; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_GetSizeMax | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_GetSizeMax(IMoniker* iface, | |
| ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */ | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| TRACE("(%p,%p)\n",This,pcbSize); | |
| if(!pcbSize) | |
| return E_INVALIDARG; | |
| pcbSize->u.LowPart = sizeof(ULONG) + (strlenW(This->URLName) * sizeof(WCHAR)); | |
| pcbSize->u.HighPart = 0; | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_BindToObject | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_BindToObject(IMoniker* iface, | |
| IBindCtx* pbc, | |
| IMoniker* pmkToLeft, | |
| REFIID riid, | |
| VOID** ppvResult) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| *ppvResult=0; | |
| FIXME("(%p)->(%p,%p,%s,%p): stub\n",This,pbc,pmkToLeft,debugstr_guid(riid), | |
| ppvResult); | |
| return E_NOTIMPL; | |
| } | |
| typedef struct { | |
| enum {OnProgress, OnDataAvailable} callback; | |
| } URLMON_CallbackData; | |
| #if 0 | |
| static LRESULT CALLBACK URLMON_WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) | |
| { | |
| return DefWindowProcA(hwnd, msg, wparam, lparam); | |
| } | |
| static void PostOnProgress(URLMonikerImpl *This, UINT progress, UINT maxprogress, DWORD status, LPCWSTR *str) | |
| { | |
| } | |
| static void CALLBACK URLMON_InternetCallback(HINTERNET hinet, /*DWORD_PTR*/ DWORD context, DWORD status, | |
| void *status_info, DWORD status_info_len) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)context; | |
| TRACE("handle %p this %p status %08lx\n", hinet, This, status); | |
| if(This->filesize == -1) { | |
| switch(status) { | |
| case INTERNET_STATUS_RESOLVING_NAME: | |
| PostOnProgess(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, status_info); | |
| break; | |
| case INTERNET_STATUS_CONNECTING_TO_SERVER: | |
| PostOnProgress(This, 0, 0, BINDSTATUS_CONNECTING, NULL); | |
| break; | |
| case INTERNET_STATUS_SENDING_REQUEST: | |
| PostOnProgress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL); | |
| break; | |
| case INTERNET_REQUEST_COMPLETE: | |
| { | |
| DWORD len, lensz = sizeof(len); | |
| HttpQueryInfoW(hrequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &len, &lensz, NULL); | |
| TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), len); | |
| This->filesize = len; | |
| break; | |
| } | |
| } | |
| } | |
| return; | |
| } | |
| #endif | |
| /****************************************************************************** | |
| * URLMoniker_BindToStorage | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface, | |
| IBindCtx* pbc, | |
| IMoniker* pmkToLeft, | |
| REFIID riid, | |
| VOID** ppvObject) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| HRESULT hres; | |
| IBindStatusCallback *pbscb; | |
| BINDINFO bi; | |
| DWORD bindf; | |
| IStream *pstr; | |
| FIXME("(%p)->(%p,%p,%s,%p): stub\n",This,pbc,pmkToLeft,debugstr_guid(riid),ppvObject); | |
| if(pmkToLeft) { | |
| FIXME("pmkToLeft != NULL\n"); | |
| return E_NOTIMPL; | |
| } | |
| if(!IsEqualIID(&IID_IStream, riid)) { | |
| FIXME("unsupported iid\n"); | |
| return E_NOTIMPL; | |
| } | |
| /* FIXME This is a bad hack (tm). We should clearly download to a temporary file. | |
| We also need to implement IStream ourselves so that IStream_Read can return | |
| E_PENDING */ | |
| hres = CreateStreamOnHGlobal(0, TRUE, &pstr); | |
| if(SUCCEEDED(hres)) { | |
| TRACE("Created dummy stream...\n"); | |
| hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&pbscb); | |
| if(SUCCEEDED(hres)) { | |
| TRACE("Got IBindStatusCallback...\n"); | |
| memset(&bi, 0, sizeof(bi)); | |
| bi.cbSize = sizeof(bi); | |
| bindf = 0; | |
| hres = IBindStatusCallback_GetBindInfo(pbscb, &bindf, &bi); | |
| if(SUCCEEDED(hres)) { | |
| URL_COMPONENTSW url; | |
| WCHAR *host, *path; | |
| DWORD len, lensz = sizeof(len), total_read = 0; | |
| LARGE_INTEGER last_read_pos; | |
| FORMATETC fmt; | |
| STGMEDIUM stg; | |
| TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n", | |
| bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid)); | |
| hres = IBindStatusCallback_OnStartBinding(pbscb, 0, (IBinding*)&This->lpvtbl2); | |
| TRACE("OnStartBinding rets %08lx\n", hres); | |
| #if 0 | |
| if(!registered_wndclass) { | |
| WNDCLASSA urlmon_wndclass = {0, URLMON_WndProc,0, 0, URLMON_hInstance, 0, 0, 0, NULL, "URLMON_Callback_Window_Class"}; | |
| RegisterClassA(&urlmon_wndclass); | |
| registered_wndclass = TRUE; | |
| } | |
| This->hwndCallback = CreateWindowA("URLMON_Callback_Window_Class", NULL, 0, 0, 0, 0, 0, 0, 0, | |
| URLMON_hInstance, NULL); | |
| #endif | |
| memset(&url, 0, sizeof(url)); | |
| url.dwStructSize = sizeof(url); | |
| url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = 1; | |
| InternetCrackUrlW(This->URLName, 0, 0, &url); | |
| host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR)); | |
| memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR)); | |
| host[url.dwHostNameLength] = '\0'; | |
| path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR)); | |
| memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR)); | |
| path[url.dwUrlPathLength] = '\0'; | |
| This->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/); | |
| /* InternetSetStatusCallback(This->hinternet, URLMON_InternetCallback);*/ | |
| This->hconnect = InternetConnectW(This->hinternet, host, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, | |
| INTERNET_SERVICE_HTTP, 0, (DWORD)This); | |
| This->hrequest = HttpOpenRequestW(This->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)This); | |
| hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, 0x22, NULL); | |
| hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL); | |
| hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL); | |
| hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL); | |
| hres = E_OUTOFMEMORY; /* FIXME */ | |
| if(HttpSendRequestW(This->hrequest, NULL, 0, NULL, 0)) { | |
| len = 0; | |
| HttpQueryInfoW(This->hrequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &len, &lensz, NULL); | |
| TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), len); | |
| last_read_pos.u.LowPart = last_read_pos.u.HighPart = 0; | |
| fmt.cfFormat = 0; | |
| fmt.ptd = NULL; | |
| fmt.dwAspect = 0; | |
| fmt.lindex = -1; | |
| fmt.tymed = TYMED_ISTREAM; | |
| stg.tymed = TYMED_ISTREAM; | |
| stg.u.pstm = pstr; | |
| stg.pUnkForRelease = NULL; | |
| while(1) { | |
| char buf[4096]; | |
| DWORD bufread; | |
| DWORD written; | |
| if(InternetReadFile(This->hrequest, buf, sizeof(buf), &bufread)) { | |
| TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10)); | |
| if(bufread == 0) break; | |
| IStream_Write(pstr, buf, bufread, &written); | |
| total_read += bufread; | |
| IStream_Seek(pstr, last_read_pos, STREAM_SEEK_SET, NULL); | |
| hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, (total_read == bufread) ? | |
| BINDSTATUS_BEGINDOWNLOADDATA : | |
| BINDSTATUS_DOWNLOADINGDATA, NULL); | |
| hres = IBindStatusCallback_OnDataAvailable(pbscb, | |
| (total_read == bufread) ? BSCF_FIRSTDATANOTIFICATION : | |
| BSCF_INTERMEDIATEDATANOTIFICATION, | |
| total_read, &fmt, &stg); | |
| last_read_pos.u.LowPart += bufread; /* FIXME */ | |
| } else | |
| break; | |
| } | |
| hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, BINDSTATUS_ENDDOWNLOADDATA, NULL); | |
| hres = IBindStatusCallback_OnDataAvailable(pbscb, BSCF_LASTDATANOTIFICATION, total_read, &fmt, &stg); | |
| TRACE("OnDataAvail rets %08lx\n", hres); | |
| hres = IBindStatusCallback_OnStopBinding(pbscb, S_OK, NULL); | |
| TRACE("OnStop rets %08lx\n", hres); | |
| hres = S_OK; | |
| } | |
| InternetCloseHandle(This->hrequest); | |
| InternetCloseHandle(This->hconnect); | |
| InternetCloseHandle(This->hinternet); | |
| IBindStatusCallback_Release(pbscb); | |
| } | |
| } | |
| } | |
| *ppvObject = (VOID*)pstr; | |
| return hres; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_Reduce | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_Reduce(IMoniker* iface, | |
| IBindCtx* pbc, | |
| DWORD dwReduceHowFar, | |
| IMoniker** ppmkToLeft, | |
| IMoniker** ppmkReduced) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| TRACE("(%p,%p,%ld,%p,%p)\n",This,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); | |
| if(!ppmkReduced) | |
| return E_INVALIDARG; | |
| URLMonikerImpl_AddRef(iface); | |
| *ppmkReduced = iface; | |
| return MK_S_REDUCED_TO_SELF; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_ComposeWith | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_ComposeWith(IMoniker* iface, | |
| IMoniker* pmkRight, | |
| BOOL fOnlyIfNotGeneric, | |
| IMoniker** ppmkComposite) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite); | |
| return E_NOTIMPL; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_Enum | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| TRACE("(%p,%d,%p)\n",This,fForward,ppenumMoniker); | |
| if(!ppenumMoniker) | |
| return E_INVALIDARG; | |
| /* Does not support sub-monikers */ | |
| *ppenumMoniker = NULL; | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_IsEqual | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| CLSID clsid; | |
| LPOLESTR urlPath; | |
| IBindCtx* bind; | |
| HRESULT res; | |
| TRACE("(%p,%p)\n",This,pmkOtherMoniker); | |
| if(pmkOtherMoniker==NULL) | |
| return E_INVALIDARG; | |
| IMoniker_GetClassID(pmkOtherMoniker,&clsid); | |
| if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker)) | |
| return S_FALSE; | |
| res = CreateBindCtx(0,&bind); | |
| if(FAILED(res)) | |
| return res; | |
| res = S_FALSE; | |
| if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) { | |
| int result = lstrcmpiW(urlPath, This->URLName); | |
| CoTaskMemFree(urlPath); | |
| if(result == 0) | |
| res = S_OK; | |
| } | |
| IUnknown_Release(bind); | |
| return res; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_Hash | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| int h = 0,i,skip,len; | |
| int off = 0; | |
| LPOLESTR val; | |
| TRACE("(%p,%p)\n",This,pdwHash); | |
| if(!pdwHash) | |
| return E_INVALIDARG; | |
| val = This->URLName; | |
| len = lstrlenW(val); | |
| if(len < 16) { | |
| for(i = len ; i > 0; i--) { | |
| h = (h * 37) + val[off++]; | |
| } | |
| } | |
| else { | |
| /* only sample some characters */ | |
| skip = len / 8; | |
| for(i = len; i > 0; i -= skip, off += skip) { | |
| h = (h * 39) + val[off]; | |
| } | |
| } | |
| *pdwHash = h; | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_IsRunning | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_IsRunning(IMoniker* iface, | |
| IBindCtx* pbc, | |
| IMoniker* pmkToLeft, | |
| IMoniker* pmkNewlyRunning) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning); | |
| return E_NOTIMPL; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_GetTimeOfLastChange | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_GetTimeOfLastChange(IMoniker* iface, | |
| IBindCtx* pbc, | |
| IMoniker* pmkToLeft, | |
| FILETIME* pFileTime) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pFileTime); | |
| return E_NOTIMPL; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_Inverse | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| TRACE("(%p,%p)\n",This,ppmk); | |
| return MK_E_NOINVERSE; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_CommonPrefixWith | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix); | |
| return E_NOTIMPL; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_RelativePathTo | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath); | |
| return E_NOTIMPL; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_GetDisplayName | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_GetDisplayName(IMoniker* iface, | |
| IBindCtx* pbc, | |
| IMoniker* pmkToLeft, | |
| LPOLESTR *ppszDisplayName) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| int len; | |
| TRACE("(%p,%p,%p,%p)\n",This,pbc,pmkToLeft,ppszDisplayName); | |
| if(!ppszDisplayName) | |
| return E_INVALIDARG; | |
| /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context, | |
| then look at pmkToLeft to try and complete the URL | |
| */ | |
| len = lstrlenW(This->URLName)+1; | |
| *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR)); | |
| if(!*ppszDisplayName) | |
| return E_OUTOFMEMORY; | |
| lstrcpyW(*ppszDisplayName, This->URLName); | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_ParseDisplayName | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_ParseDisplayName(IMoniker* iface, | |
| IBindCtx* pbc, | |
| IMoniker* pmkToLeft, | |
| LPOLESTR pszDisplayName, | |
| ULONG* pchEaten, | |
| IMoniker** ppmkOut) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut); | |
| return E_NOTIMPL; | |
| } | |
| /****************************************************************************** | |
| * URLMoniker_IsSystemMoniker | |
| ******************************************************************************/ | |
| static HRESULT WINAPI URLMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) | |
| { | |
| URLMonikerImpl *This = (URLMonikerImpl *)iface; | |
| TRACE("(%p,%p)\n",This,pwdMksys); | |
| if(!pwdMksys) | |
| return E_INVALIDARG; | |
| *pwdMksys = MKSYS_URLMONIKER; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI URLMonikerImpl_IBinding_QueryInterface(IBinding* iface,REFIID riid,void** ppvObject) | |
| { | |
| ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); | |
| TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); | |
| /* Perform a sanity check on the parameters.*/ | |
| if ( (This==0) || (ppvObject==0) ) | |
| return E_INVALIDARG; | |
| /* Initialize the return parameter */ | |
| *ppvObject = 0; | |
| /* Compare the riid with the interface IDs implemented by this object.*/ | |
| if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IBinding, riid)) | |
| *ppvObject = iface; | |
| /* Check that we obtained an interface.*/ | |
| if ((*ppvObject)==0) | |
| return E_NOINTERFACE; | |
| /* Query Interface always increases the reference count by one when it is successful */ | |
| IBinding_AddRef(iface); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI URLMonikerImpl_IBinding_AddRef(IBinding* iface) | |
| { | |
| ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); | |
| TRACE("(%p)\n",This); | |
| return URLMonikerImpl_AddRef((IMoniker*)This); | |
| } | |
| static ULONG WINAPI URLMonikerImpl_IBinding_Release(IBinding* iface) | |
| { | |
| ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); | |
| TRACE("(%p)\n",This); | |
| return URLMonikerImpl_Release((IMoniker*)This); | |
| } | |
| static HRESULT WINAPI URLMonikerImpl_IBinding_Abort(IBinding* iface) | |
| { | |
| ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI URLMonikerImpl_IBinding_GetBindResult(IBinding* iface, CLSID* pclsidProtocol, DWORD* pdwResult, LPOLESTR* pszResult, DWORD* pdwReserved) | |
| { | |
| ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); | |
| FIXME("(%p)->(%p, %p, %p, %p): stub\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI URLMonikerImpl_IBinding_GetPriority(IBinding* iface, LONG* pnPriority) | |
| { | |
| ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); | |
| FIXME("(%p)->(%p): stub\n", This, pnPriority); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI URLMonikerImpl_IBinding_Resume(IBinding* iface) | |
| { | |
| ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI URLMonikerImpl_IBinding_SetPriority(IBinding* iface, LONG nPriority) | |
| { | |
| ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); | |
| FIXME("(%p)->(%ld): stub\n", This, nPriority); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI URLMonikerImpl_IBinding_Suspend(IBinding* iface) | |
| { | |
| ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); | |
| FIXME("(%p): stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| /********************************************************************************/ | |
| /* Virtual function table for the URLMonikerImpl class which include IPersist,*/ | |
| /* IPersistStream and IMoniker functions. */ | |
| static IMonikerVtbl VT_URLMonikerImpl = | |
| { | |
| URLMonikerImpl_QueryInterface, | |
| URLMonikerImpl_AddRef, | |
| URLMonikerImpl_Release, | |
| URLMonikerImpl_GetClassID, | |
| URLMonikerImpl_IsDirty, | |
| URLMonikerImpl_Load, | |
| URLMonikerImpl_Save, | |
| URLMonikerImpl_GetSizeMax, | |
| URLMonikerImpl_BindToObject, | |
| URLMonikerImpl_BindToStorage, | |
| URLMonikerImpl_Reduce, | |
| URLMonikerImpl_ComposeWith, | |
| URLMonikerImpl_Enum, | |
| URLMonikerImpl_IsEqual, | |
| URLMonikerImpl_Hash, | |
| URLMonikerImpl_IsRunning, | |
| URLMonikerImpl_GetTimeOfLastChange, | |
| URLMonikerImpl_Inverse, | |
| URLMonikerImpl_CommonPrefixWith, | |
| URLMonikerImpl_RelativePathTo, | |
| URLMonikerImpl_GetDisplayName, | |
| URLMonikerImpl_ParseDisplayName, | |
| URLMonikerImpl_IsSystemMoniker | |
| }; | |
| static IBindingVtbl VTBinding_URLMonikerImpl = | |
| { | |
| URLMonikerImpl_IBinding_QueryInterface, | |
| URLMonikerImpl_IBinding_AddRef, | |
| URLMonikerImpl_IBinding_Release, | |
| URLMonikerImpl_IBinding_Abort, | |
| URLMonikerImpl_IBinding_Suspend, | |
| URLMonikerImpl_IBinding_Resume, | |
| URLMonikerImpl_IBinding_SetPriority, | |
| URLMonikerImpl_IBinding_GetPriority, | |
| URLMonikerImpl_IBinding_GetBindResult | |
| }; | |
| /****************************************************************************** | |
| * URLMoniker_Construct (local function) | |
| *******************************************************************************/ | |
| static HRESULT URLMonikerImpl_Construct(URLMonikerImpl* This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName) | |
| { | |
| HRESULT hres; | |
| DWORD sizeStr; | |
| TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName)); | |
| memset(This, 0, sizeof(*This)); | |
| /* Initialize the virtual function table. */ | |
| This->lpvtbl1 = &VT_URLMonikerImpl; | |
| This->lpvtbl2 = &VTBinding_URLMonikerImpl; | |
| This->ref = 0; | |
| if(lpszLeftURLName) { | |
| hres = UrlCombineW(lpszLeftURLName, lpszURLName, NULL, &sizeStr, 0); | |
| if(FAILED(hres)) { | |
| return hres; | |
| } | |
| sizeStr++; | |
| } | |
| else | |
| sizeStr = lstrlenW(lpszURLName)+1; | |
| This->URLName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr)); | |
| if (This->URLName==NULL) | |
| return E_OUTOFMEMORY; | |
| if(lpszLeftURLName) { | |
| hres = UrlCombineW(lpszLeftURLName, lpszURLName, This->URLName, &sizeStr, 0); | |
| if(FAILED(hres)) { | |
| HeapFree(GetProcessHeap(), 0, This->URLName); | |
| return hres; | |
| } | |
| } | |
| else | |
| strcpyW(This->URLName,lpszURLName); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * CreateAsyncBindCtx (URLMON.@) | |
| */ | |
| HRESULT WINAPI CreateAsyncBindCtx(DWORD reserved, IBindStatusCallback *callback, | |
| IEnumFORMATETC *format, IBindCtx **pbind) | |
| { | |
| HRESULT hres; | |
| BIND_OPTS bindopts; | |
| IBindCtx *bctx; | |
| TRACE("(%08lx %p %p %p)\n", reserved, callback, format, pbind); | |
| if(!callback) | |
| return E_INVALIDARG; | |
| if(format) | |
| FIXME("format is not supported yet\n"); | |
| hres = CreateBindCtx(0, &bctx); | |
| if(FAILED(hres)) | |
| return hres; | |
| bindopts.cbStruct = sizeof(BIND_OPTS); | |
| bindopts.grfFlags = BIND_MAYBOTHERUSER; | |
| bindopts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE; | |
| bindopts.dwTickCountDeadline = 0; | |
| IBindCtx_SetBindOptions(bctx, &bindopts); | |
| hres = IBindCtx_RegisterObjectParam(bctx, (LPOLESTR)BSCBHolder, (IUnknown*)callback); | |
| if(FAILED(hres)) { | |
| IBindCtx_Release(bctx); | |
| return hres; | |
| } | |
| *pbind = bctx; | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * CreateAsyncBindCtxEx (URLMON.@) | |
| * | |
| * Create an asynchronous bind context. | |
| * | |
| * FIXME | |
| * Not implemented. | |
| */ | |
| HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options, | |
| IBindStatusCallback *callback, IEnumFORMATETC *format, IBindCtx** pbind, | |
| DWORD reserved) | |
| { | |
| FIXME("stub, returns failure\n"); | |
| return E_INVALIDARG; | |
| } | |
| /*********************************************************************** | |
| * CreateURLMoniker (URLMON.@) | |
| * | |
| * Create a url moniker. | |
| * | |
| * PARAMS | |
| * pmkContext [I] Context | |
| * szURL [I] Url to create the moniker for | |
| * ppmk [O] Destination for created moniker. | |
| * | |
| * RETURNS | |
| * Success: S_OK. ppmk contains the created IMoniker object. | |
| * Failure: MK_E_SYNTAX if szURL is not a valid url, or | |
| * E_OUTOFMEMORY if memory allocation fails. | |
| */ | |
| HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk) | |
| { | |
| URLMonikerImpl *obj; | |
| HRESULT hres; | |
| IID iid = IID_IMoniker; | |
| LPOLESTR lefturl = NULL; | |
| TRACE("(%p, %s, %p)\n", pmkContext, debugstr_w(szURL), ppmk); | |
| if(!(obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)))) | |
| return E_OUTOFMEMORY; | |
| if(pmkContext) { | |
| CLSID clsid; | |
| IBindCtx* bind; | |
| IMoniker_GetClassID(pmkContext, &clsid); | |
| if(IsEqualCLSID(&clsid, &CLSID_StdURLMoniker) && SUCCEEDED(CreateBindCtx(0, &bind))) { | |
| URLMonikerImpl_GetDisplayName(pmkContext, bind, NULL, &lefturl); | |
| IBindCtx_Release(bind); | |
| } | |
| } | |
| hres = URLMonikerImpl_Construct(obj, lefturl, szURL); | |
| CoTaskMemFree(lefturl); | |
| if(SUCCEEDED(hres)) | |
| hres = URLMonikerImpl_QueryInterface((IMoniker*)obj, &iid, (void**)ppmk); | |
| else | |
| HeapFree(GetProcessHeap(), 0, obj); | |
| return hres; | |
| } | |
| /*********************************************************************** | |
| * CoInternetGetSession (URLMON.@) | |
| * | |
| * Create a new internet session and return an IInternetSession interface | |
| * representing it. | |
| * | |
| * PARAMS | |
| * dwSessionMode [I] Mode for the internet session | |
| * ppIInternetSession [O] Destination for creates IInternetSession object | |
| * dwReserved [I] Reserved, must be 0. | |
| * | |
| * RETURNS | |
| * Success: S_OK. ppIInternetSession contains the IInternetSession interface. | |
| * Failure: E_INVALIDARG, if any argument is invalid, or | |
| * E_OUTOFMEMORY if memory allocation fails. | |
| */ | |
| HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession, DWORD dwReserved) | |
| { | |
| FIXME("(%ld, %p, %ld): stub\n", dwSessionMode, ppIInternetSession, dwReserved); | |
| if(dwSessionMode) { | |
| ERR("dwSessionMode: %ld, must be zero\n", dwSessionMode); | |
| } | |
| if(dwReserved) { | |
| ERR("dwReserved: %ld, must be zero\n", dwReserved); | |
| } | |
| *ppIInternetSession=NULL; | |
| return E_OUTOFMEMORY; | |
| } | |
| /*********************************************************************** | |
| * CoInternetQueryInfo (URLMON.@) | |
| * | |
| * Retrieves information relevant to a specified URL | |
| * | |
| * RETURNS | |
| * S_OK success | |
| * S_FALSE buffer too small | |
| * INET_E_QUERYOPTIONUNKNOWN invalid option | |
| * | |
| */ | |
| HRESULT WINAPI CoInternetQueryInfo(LPCWSTR pwzUrl, QUERYOPTION QueryOption, | |
| DWORD dwQueryFlags, LPVOID pvBuffer, DWORD cbBuffer, DWORD * pcbBuffer, | |
| DWORD dwReserved) | |
| { | |
| FIXME("(%s, %x, %lx, %p, %lx, %p, %lx): stub\n", debugstr_w(pwzUrl), | |
| QueryOption, dwQueryFlags, pvBuffer, cbBuffer, pcbBuffer, dwReserved); | |
| return S_OK; | |
| } | |
| static BOOL URLMON_IsBinary(LPVOID pBuffer, DWORD cbSize) | |
| { | |
| unsigned int i, binarycount = 0; | |
| unsigned char *buff = pBuffer; | |
| for(i=0; i<cbSize; i++) { | |
| if(buff[i] < 32) | |
| binarycount++; | |
| } | |
| return binarycount > (cbSize-binarycount); | |
| } | |
| /*********************************************************************** | |
| * FindMimeFromData (URLMON.@) | |
| * | |
| * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided. | |
| * | |
| * NOTE | |
| * See http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp | |
| */ | |
| HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer, | |
| DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags, | |
| LPWSTR* ppwzMimeOut, DWORD dwReserved) | |
| { | |
| static const WCHAR szBinaryMime[] = {'a','p','p','l','i','c','a','t','i','o','n','/','o','c','t','e','t','-','s','t','r','e','a','m','\0'}; | |
| static const WCHAR szTextMime[] = {'t','e','x','t','/','p','l','a','i','n','\0'}; | |
| static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'}; | |
| WCHAR szTmpMime[256]; | |
| LPCWSTR mimeType = NULL; | |
| HKEY hKey = NULL; | |
| TRACE("(%p,%s,%p,%ld,%s,0x%lx,%p,0x%lx)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize, | |
| debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved); | |
| if((!pwzUrl && (!pBuffer || cbSize <= 0)) || !ppwzMimeOut) | |
| return E_INVALIDARG; | |
| if(pwzMimeProposed) | |
| mimeType = pwzMimeProposed; | |
| else { | |
| /* Try and find the mime type in the registry */ | |
| if(pwzUrl) { | |
| LPWSTR ext = strrchrW(pwzUrl, '.'); | |
| if(ext) { | |
| DWORD dwSize; | |
| if(!RegOpenKeyExW(HKEY_CLASSES_ROOT, ext, 0, 0, &hKey)) { | |
| if(!RegQueryValueExW(hKey, szContentType, NULL, NULL, (LPBYTE)szTmpMime, &dwSize)) { | |
| mimeType = szTmpMime; | |
| } | |
| RegCloseKey(hKey); | |
| } | |
| } | |
| } | |
| } | |
| if(!mimeType && pBuffer && cbSize > 0) | |
| mimeType = URLMON_IsBinary(pBuffer, cbSize)?szBinaryMime:szTextMime; | |
| TRACE("Using %s\n", debugstr_w(mimeType)); | |
| *ppwzMimeOut = CoTaskMemAlloc((lstrlenW(mimeType)+1)*sizeof(WCHAR)); | |
| if(!*ppwzMimeOut) return E_OUTOFMEMORY; | |
| lstrcpyW(*ppwzMimeOut, mimeType); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * IsAsyncMoniker (URLMON.@) | |
| */ | |
| HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk) | |
| { | |
| IUnknown *am; | |
| TRACE("(%p)\n", pmk); | |
| if(!pmk) | |
| return E_INVALIDARG; | |
| if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) { | |
| IUnknown_Release(am); | |
| return S_OK; | |
| } | |
| return S_FALSE; | |
| } | |
| /*********************************************************************** | |
| * RegisterBindStatusCallback (URLMON.@) | |
| * | |
| * Register a bind status callback. | |
| * | |
| * PARAMS | |
| * pbc [I] Binding context | |
| * pbsc [I] Callback to register | |
| * ppbscPrevious [O] Destination for previous callback | |
| * dwReserved [I] Reserved, must be 0. | |
| * | |
| * RETURNS | |
| * Success: S_OK. | |
| * Failure: E_INVALIDARG, if any argument is invalid, or | |
| * E_OUTOFMEMORY if memory allocation fails. | |
| */ | |
| HRESULT WINAPI RegisterBindStatusCallback( | |
| IBindCtx *pbc, | |
| IBindStatusCallback *pbsc, | |
| IBindStatusCallback **ppbscPrevious, | |
| DWORD dwReserved) | |
| { | |
| IBindStatusCallback *prev; | |
| TRACE("(%p,%p,%p,%lu)\n", pbc, pbsc, ppbscPrevious, dwReserved); | |
| if (pbc == NULL || pbsc == NULL) | |
| return E_INVALIDARG; | |
| if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&prev))) | |
| { | |
| IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder); | |
| if (ppbscPrevious) | |
| *ppbscPrevious = prev; | |
| else | |
| IBindStatusCallback_Release(prev); | |
| } | |
| return IBindCtx_RegisterObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown *)pbsc); | |
| } | |
| /*********************************************************************** | |
| * RevokeBindStatusCallback (URLMON.@) | |
| * | |
| * Unregister a bind status callback. | |
| * | |
| * pbc [I] Binding context | |
| * pbsc [I] Callback to unregister | |
| * | |
| * RETURNS | |
| * Success: S_OK. | |
| * Failure: E_INVALIDARG, if any argument is invalid, or | |
| * E_FAIL if pbsc wasn't registered with pbc. | |
| */ | |
| HRESULT WINAPI RevokeBindStatusCallback( | |
| IBindCtx *pbc, | |
| IBindStatusCallback *pbsc) | |
| { | |
| IBindStatusCallback *callback; | |
| HRESULT hr = E_FAIL; | |
| TRACE("(%p,%p)\n", pbc, pbsc); | |
| if (pbc == NULL || pbsc == NULL) | |
| return E_INVALIDARG; | |
| if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&callback))) | |
| { | |
| if (callback == pbsc) | |
| { | |
| IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder); | |
| hr = S_OK; | |
| } | |
| IBindStatusCallback_Release(pbsc); | |
| } | |
| return hr; | |
| } | |
| /*********************************************************************** | |
| * ReleaseBindInfo (URLMON.@) | |
| * | |
| * Release the resources used by the specified BINDINFO structure. | |
| * | |
| * PARAMS | |
| * pbindinfo [I] BINDINFO to release. | |
| * | |
| * RETURNS | |
| * Nothing. | |
| */ | |
| void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo) | |
| { | |
| FIXME("(%p)stub!\n", pbindinfo); | |
| } | |
| /*********************************************************************** | |
| * URLDownloadToFileA (URLMON.@) | |
| * | |
| * Downloads URL szURL to rile szFileName and call lpfnCB callback to | |
| * report progress. | |
| * | |
| * PARAMS | |
| * pCaller [I] controlling IUnknown interface. | |
| * szURL [I] URL of the file to download | |
| * szFileName [I] file name to store the content of the URL | |
| * dwReserved [I] reserved - set to 0 | |
| * lpfnCB [I] callback for progress report | |
| * | |
| * RETURNS | |
| * S_OK on success | |
| * E_OUTOFMEMORY when going out of memory | |
| */ | |
| HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller, | |
| LPCSTR szURL, | |
| LPCSTR szFileName, | |
| DWORD dwReserved, | |
| LPBINDSTATUSCALLBACK lpfnCB) | |
| { | |
| UNICODE_STRING szURL_w, szFileName_w; | |
| if ((szURL == NULL) || (szFileName == NULL)) { | |
| FIXME("(%p,%s,%s,%08lx,%p) cannot accept NULL strings !\n", pCaller, debugstr_a(szURL), debugstr_a(szFileName), dwReserved, lpfnCB); | |
| return E_INVALIDARG; /* The error code is not specified in this case... */ | |
| } | |
| if (RtlCreateUnicodeStringFromAsciiz(&szURL_w, szURL)) { | |
| if (RtlCreateUnicodeStringFromAsciiz(&szFileName_w, szFileName)) { | |
| HRESULT ret = URLDownloadToFileW(pCaller, szURL_w.Buffer, szFileName_w.Buffer, dwReserved, lpfnCB); | |
| RtlFreeUnicodeString(&szURL_w); | |
| RtlFreeUnicodeString(&szFileName_w); | |
| return ret; | |
| } else { | |
| RtlFreeUnicodeString(&szURL_w); | |
| } | |
| } | |
| FIXME("(%p,%s,%s,%08lx,%p) could not allocate W strings !\n", pCaller, szURL, szFileName, dwReserved, lpfnCB); | |
| return E_OUTOFMEMORY; | |
| } | |
| /*********************************************************************** | |
| * URLDownloadToFileW (URLMON.@) | |
| * | |
| * Downloads URL szURL to rile szFileName and call lpfnCB callback to | |
| * report progress. | |
| * | |
| * PARAMS | |
| * pCaller [I] controlling IUnknown interface. | |
| * szURL [I] URL of the file to download | |
| * szFileName [I] file name to store the content of the URL | |
| * dwReserved [I] reserved - set to 0 | |
| * lpfnCB [I] callback for progress report | |
| * | |
| * RETURNS | |
| * S_OK on success | |
| * E_OUTOFMEMORY when going out of memory | |
| */ | |
| HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller, | |
| LPCWSTR szURL, | |
| LPCWSTR szFileName, | |
| DWORD dwReserved, | |
| LPBINDSTATUSCALLBACK lpfnCB) | |
| { | |
| HINTERNET hinternet, hcon, hreq; | |
| BOOL r; | |
| CHAR buffer[0x1000]; | |
| DWORD sz, total, written; | |
| DWORD total_size = 0xFFFFFFFF, arg_size = sizeof(total_size); | |
| URL_COMPONENTSW url; | |
| WCHAR host[0x80], path[0x100]; | |
| HANDLE hfile; | |
| static const WCHAR wszAppName[]={'u','r','l','m','o','n','.','d','l','l',0}; | |
| /* Note: all error codes would need to be checked agains real Windows behaviour... */ | |
| TRACE("(%p,%s,%s,%08lx,%p) stub!\n", pCaller, debugstr_w(szURL), debugstr_w(szFileName), dwReserved, lpfnCB); | |
| if ((szURL == NULL) || (szFileName == NULL)) { | |
| FIXME(" cannot accept NULL strings !\n"); | |
| return E_INVALIDARG; | |
| } | |
| /* Would be better to use the application name here rather than 'urlmon' :-/ */ | |
| hinternet = InternetOpenW(wszAppName, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); | |
| if (hinternet == NULL) { | |
| return E_OUTOFMEMORY; | |
| } | |
| memset(&url, 0, sizeof(url)); | |
| url.dwStructSize = sizeof(url); | |
| url.lpszHostName = host; | |
| url.dwHostNameLength = sizeof(host); | |
| url.lpszUrlPath = path; | |
| url.dwUrlPathLength = sizeof(path); | |
| if (!InternetCrackUrlW(szURL, 0, 0, &url)) { | |
| InternetCloseHandle(hinternet); | |
| return E_OUTOFMEMORY; | |
| } | |
| if (lpfnCB) { | |
| if (IBindStatusCallback_OnProgress(lpfnCB, 0, 0, BINDSTATUS_CONNECTING, url.lpszHostName) == E_ABORT) { | |
| InternetCloseHandle(hinternet); | |
| return S_OK; | |
| } | |
| } | |
| hcon = InternetConnectW(hinternet, url.lpszHostName, url.nPort, | |
| url.lpszUserName, url.lpszPassword, | |
| INTERNET_SERVICE_HTTP, 0, 0); | |
| if (!hcon) { | |
| InternetCloseHandle(hinternet); | |
| return E_OUTOFMEMORY; | |
| } | |
| hreq = HttpOpenRequestW(hcon, NULL, url.lpszUrlPath, NULL, NULL, NULL, 0, 0); | |
| if (!hreq) { | |
| InternetCloseHandle(hinternet); | |
| InternetCloseHandle(hcon); | |
| return E_OUTOFMEMORY; | |
| } | |
| if (!HttpSendRequestW(hreq, NULL, 0, NULL, 0)) { | |
| InternetCloseHandle(hinternet); | |
| InternetCloseHandle(hcon); | |
| InternetCloseHandle(hreq); | |
| return E_OUTOFMEMORY; | |
| } | |
| if (HttpQueryInfoW(hreq, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, | |
| &total_size, &arg_size, NULL)) { | |
| TRACE(" total size : %ld\n", total_size); | |
| } | |
| hfile = CreateFileW(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, | |
| FILE_ATTRIBUTE_NORMAL, NULL ); | |
| if (hfile == INVALID_HANDLE_VALUE) { | |
| return E_ACCESSDENIED; | |
| } | |
| if (lpfnCB) { | |
| if (IBindStatusCallback_OnProgress(lpfnCB, 0, total_size != 0xFFFFFFFF ? total_size : 0, | |
| BINDSTATUS_BEGINDOWNLOADDATA, szURL) == E_ABORT) { | |
| InternetCloseHandle(hreq); | |
| InternetCloseHandle(hcon); | |
| InternetCloseHandle(hinternet); | |
| CloseHandle(hfile); | |
| return S_OK; | |
| } | |
| } | |
| total = 0; | |
| while (1) { | |
| r = InternetReadFile(hreq, buffer, sizeof(buffer), &sz); | |
| if (!r) { | |
| InternetCloseHandle(hreq); | |
| InternetCloseHandle(hcon); | |
| InternetCloseHandle(hinternet); | |
| CloseHandle(hfile); | |
| return E_OUTOFMEMORY; | |
| } | |
| if (!sz) | |
| break; | |
| total += sz; | |
| if (lpfnCB) { | |
| if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0, | |
| BINDSTATUS_DOWNLOADINGDATA, szURL) == E_ABORT) { | |
| InternetCloseHandle(hreq); | |
| InternetCloseHandle(hcon); | |
| InternetCloseHandle(hinternet); | |
| CloseHandle(hfile); | |
| return S_OK; | |
| } | |
| } | |
| if (!WriteFile(hfile, buffer, sz, &written, NULL)) { | |
| InternetCloseHandle(hreq); | |
| InternetCloseHandle(hcon); | |
| InternetCloseHandle(hinternet); | |
| CloseHandle(hfile); | |
| return E_OUTOFMEMORY; | |
| } | |
| } | |
| if (lpfnCB) { | |
| if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0, | |
| BINDSTATUS_ENDDOWNLOADDATA, szURL) == E_ABORT) { | |
| InternetCloseHandle(hreq); | |
| InternetCloseHandle(hcon); | |
| InternetCloseHandle(hinternet); | |
| CloseHandle(hfile); | |
| return S_OK; | |
| } | |
| } | |
| InternetCloseHandle(hreq); | |
| InternetCloseHandle(hcon); | |
| InternetCloseHandle(hinternet); | |
| CloseHandle(hfile); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * HlinkSimpleNavigateToString (URLMON.@) | |
| */ | |
| HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget, | |
| LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk, | |
| IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved) | |
| { | |
| FIXME("%s\n", debugstr_w( szTarget ) ); | |
| return E_NOTIMPL; | |
| } | |
| /*********************************************************************** | |
| * HlinkNavigateString (URLMON.@) | |
| */ | |
| HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget ) | |
| { | |
| TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) ); | |
| return HlinkSimpleNavigateToString( | |
| szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 ); | |
| } |