Correct bug truncating downloaded files to 4096 bytes.
[wine/multimedia.git] / dlls / urlmon / umon.c
blob4a1a512e516fd12331d99f9e5c9254bca14c211f
1 /*
2 * UrlMon
4 * Copyright 1999 Ulrich Czekalla for Corel Corporation
5 * Copyright 2002 Huw D M Davies for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define COM_NO_WINDOWS_H
23 #include <stdarg.h>
24 #include <stdio.h>
26 #define COBJMACROS
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "winternl.h"
34 #include "winuser.h"
35 #include "objbase.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "ole2.h"
39 #include "urlmon.h"
40 #include "wininet.h"
41 #include "shlwapi.h"
42 #include "urlmon_main.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
46 /* native urlmon.dll uses this key, too */
47 static const WCHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
49 /*static BOOL registered_wndclass = FALSE;*/
51 /* filemoniker data structure */
52 typedef struct URLMonikerImpl{
54 IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/
55 IBindingVtbl* lpvtbl2; /* VTable to IBinding interface */
57 ULONG ref; /* reference counter for this object */
59 LPOLESTR URLName; /* URL string identified by this URLmoniker */
61 HWND hwndCallback;
62 IBindCtx *pBC;
63 HINTERNET hinternet, hconnect, hrequest;
64 HANDLE hCacheFile;
65 IUMCacheStream *pstrCache;
66 IBindStatusCallback *pbscb;
67 DWORD total_read, expected_size;
68 } URLMonikerImpl;
70 /*******************************************************************************
71 * URLMoniker_QueryInterface
72 *******************************************************************************/
73 static HRESULT WINAPI URLMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
75 URLMonikerImpl *This = (URLMonikerImpl *)iface;
77 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
79 /* Perform a sanity check on the parameters.*/
80 if ( (This==0) || (ppvObject==0) )
81 return E_INVALIDARG;
83 /* Initialize the return parameter */
84 *ppvObject = 0;
86 /* Compare the riid with the interface IDs implemented by this object.*/
87 if (IsEqualIID(&IID_IUnknown, riid) ||
88 IsEqualIID(&IID_IPersist, riid) ||
89 IsEqualIID(&IID_IPersistStream,riid) ||
90 IsEqualIID(&IID_IMoniker, riid)
92 *ppvObject = iface;
94 /* Check that we obtained an interface.*/
95 if ((*ppvObject)==0)
96 return E_NOINTERFACE;
98 /* Query Interface always increases the reference count by one when it is successful */
99 IMoniker_AddRef(iface);
101 return S_OK;
104 /******************************************************************************
105 * URLMoniker_AddRef
106 ******************************************************************************/
107 static ULONG WINAPI URLMonikerImpl_AddRef(IMoniker* iface)
109 URLMonikerImpl *This = (URLMonikerImpl *)iface;
110 ULONG refCount = InterlockedIncrement(&This->ref);
112 TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1);
114 URLMON_LockModule();
116 return refCount;
119 /******************************************************************************
120 * URLMoniker_Release
121 ******************************************************************************/
122 static ULONG WINAPI URLMonikerImpl_Release(IMoniker* iface)
124 URLMonikerImpl *This = (URLMonikerImpl *)iface;
125 ULONG refCount = InterlockedDecrement(&This->ref);
127 TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1);
129 /* destroy the object if there's no more reference on it */
130 if (!refCount) {
131 HeapFree(GetProcessHeap(),0,This->URLName);
132 HeapFree(GetProcessHeap(),0,This);
133 if (This->hCacheFile)
134 CloseHandle(This->hCacheFile);
135 if (This->pstrCache)
137 UMCloseCacheFileStream(This->pstrCache);
138 IStream_Release((IStream *)This->pstrCache);
140 if (This->pbscb)
141 IBindStatusCallback_Release(This->pbscb);
144 URLMON_UnlockModule();
146 return refCount;
149 static void URLMonikerImpl_CloseCacheDownload(URLMonikerImpl *This)
151 CloseHandle(This->hCacheFile);
152 This->hCacheFile = 0;
153 UMCloseCacheFileStream(This->pstrCache);
154 IStream_Release((IStream *)This->pstrCache);
155 This->pstrCache = 0;
158 static HRESULT URLMonikerImpl_MoreCacheData(URLMonikerImpl *This, char *buf, DWORD dwBytes)
160 DWORD written;
162 if (WriteFile(This->hCacheFile, buf, dwBytes, &written, NULL) && written == dwBytes)
164 HRESULT hr;
166 This->total_read += written;
167 hr = IBindStatusCallback_OnProgress(This->pbscb,
168 This->total_read + written,
169 This->expected_size,
170 (This->total_read == written) ?
171 BINDSTATUS_BEGINDOWNLOADDATA :
172 BINDSTATUS_DOWNLOADINGDATA,
173 NULL);
174 if (!hr)
176 STGMEDIUM stg;
177 FORMATETC fmt;
179 fmt.cfFormat = 0;
180 fmt.ptd = NULL;
181 fmt.dwAspect = 0;
182 fmt.lindex = -1;
183 fmt.tymed = TYMED_ISTREAM;
185 stg.tymed = TYMED_ISTREAM;
186 stg.u.pstm = (IStream *)This->pstrCache;
187 stg.pUnkForRelease = NULL;
189 hr = IBindStatusCallback_OnDataAvailable(This->pbscb,
190 (This->total_read == written) ?
191 BSCF_FIRSTDATANOTIFICATION :
192 BSCF_INTERMEDIATEDATANOTIFICATION,
193 This->total_read + written,
194 &fmt,
195 &stg);
197 if (written < dwBytes)
198 return STG_E_MEDIUMFULL;
199 else
200 return hr;
202 return HRESULT_FROM_WIN32(GetLastError());
205 static void URLMonikerImpl_FinishedDownload(URLMonikerImpl *This, HRESULT hr)
207 STGMEDIUM stg;
208 FORMATETC fmt;
210 fmt.ptd = NULL;
211 fmt.dwAspect = 0;
212 fmt.lindex = -1;
213 fmt.tymed = TYMED_ISTREAM;
215 stg.tymed = TYMED_ISTREAM;
216 stg.u.pstm = (IStream *)This->pstrCache;
217 stg.pUnkForRelease = NULL;
219 IBindStatusCallback_OnProgress(This->pbscb, This->total_read, This->expected_size, BINDSTATUS_ENDDOWNLOADDATA, NULL);
220 IBindStatusCallback_OnDataAvailable(This->pbscb, BSCF_LASTDATANOTIFICATION, This->total_read, &fmt, &stg);
221 if (hr)
223 WCHAR *pwchError = 0;
225 FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
226 FORMAT_MESSAGE_ALLOCATE_BUFFER,
227 NULL, (DWORD) hr,
228 0, (LPWSTR) &pwchError,
229 0, NULL);
230 if (!pwchError)
232 static WCHAR achFormat[] = { '%', '0', '8', 'x', 0 };
234 pwchError =(WCHAR *) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * 9);
235 wsprintfW(pwchError, achFormat, hr);
237 IBindStatusCallback_OnStopBinding(This->pbscb, hr, pwchError);
238 LocalFree(pwchError);
240 else
242 IBindStatusCallback_OnStopBinding(This->pbscb, hr, NULL);
244 IBindStatusCallback_Release(This->pbscb);
245 This->pbscb = 0;
248 /******************************************************************************
249 * URLMoniker_GetClassID
250 ******************************************************************************/
251 static HRESULT WINAPI URLMonikerImpl_GetClassID(IMoniker* iface,
252 CLSID *pClassID)/* Pointer to CLSID of object */
254 URLMonikerImpl *This = (URLMonikerImpl *)iface;
256 TRACE("(%p,%p)\n",This,pClassID);
258 if (pClassID==NULL)
259 return E_POINTER;
260 /* Windows always returns CLSID_StdURLMoniker */
261 *pClassID = CLSID_StdURLMoniker;
262 return S_OK;
265 /******************************************************************************
266 * URLMoniker_IsDirty
267 ******************************************************************************/
268 static HRESULT WINAPI URLMonikerImpl_IsDirty(IMoniker* iface)
270 URLMonikerImpl *This = (URLMonikerImpl *)iface;
271 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
272 method in the OLE-provided moniker interfaces always return S_FALSE because
273 their internal state never changes. */
275 TRACE("(%p)\n",This);
277 return S_FALSE;
280 /******************************************************************************
281 * URLMoniker_Load
283 * NOTE
284 * Writes a ULONG containing length of unicode string, followed
285 * by that many unicode characters
286 ******************************************************************************/
287 static HRESULT WINAPI URLMonikerImpl_Load(IMoniker* iface,IStream* pStm)
289 URLMonikerImpl *This = (URLMonikerImpl *)iface;
291 HRESULT res;
292 ULONG len;
293 ULONG got;
294 TRACE("(%p,%p)\n",This,pStm);
296 if(!pStm)
297 return E_INVALIDARG;
299 res = IStream_Read(pStm, &len, sizeof(ULONG), &got);
300 if(SUCCEEDED(res)) {
301 if(got == sizeof(ULONG)) {
302 HeapFree(GetProcessHeap(), 0, This->URLName);
303 This->URLName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(len+1));
304 if(!This->URLName)
305 res = E_OUTOFMEMORY;
306 else {
307 res = IStream_Read(pStm, This->URLName, len, NULL);
308 This->URLName[len] = 0;
311 else
312 res = E_FAIL;
314 return res;
317 /******************************************************************************
318 * URLMoniker_Save
319 ******************************************************************************/
320 static HRESULT WINAPI URLMonikerImpl_Save(IMoniker* iface,
321 IStream* pStm,/* pointer to the stream where the object is to be saved */
322 BOOL fClearDirty)/* Specifies whether to clear the dirty flag */
324 URLMonikerImpl *This = (URLMonikerImpl *)iface;
326 HRESULT res;
327 ULONG len;
328 TRACE("(%p,%p,%d)\n",This,pStm,fClearDirty);
330 if(!pStm)
331 return E_INVALIDARG;
333 len = strlenW(This->URLName);
334 res=IStream_Write(pStm,&len,sizeof(ULONG),NULL);
335 if(SUCCEEDED(res))
336 res=IStream_Write(pStm,&This->URLName,len*sizeof(WCHAR),NULL);
337 return res;
341 /******************************************************************************
342 * URLMoniker_GetSizeMax
343 ******************************************************************************/
344 static HRESULT WINAPI URLMonikerImpl_GetSizeMax(IMoniker* iface,
345 ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */
347 URLMonikerImpl *This = (URLMonikerImpl *)iface;
349 TRACE("(%p,%p)\n",This,pcbSize);
351 if(!pcbSize)
352 return E_INVALIDARG;
354 pcbSize->u.LowPart = sizeof(ULONG) + (strlenW(This->URLName) * sizeof(WCHAR));
355 pcbSize->u.HighPart = 0;
356 return S_OK;
359 /******************************************************************************
360 * URLMoniker_BindToObject
361 ******************************************************************************/
362 static HRESULT WINAPI URLMonikerImpl_BindToObject(IMoniker* iface,
363 IBindCtx* pbc,
364 IMoniker* pmkToLeft,
365 REFIID riid,
366 VOID** ppvResult)
368 URLMonikerImpl *This = (URLMonikerImpl *)iface;
370 *ppvResult=0;
372 FIXME("(%p)->(%p,%p,%s,%p): stub\n",This,pbc,pmkToLeft,debugstr_guid(riid),
373 ppvResult);
375 return E_NOTIMPL;
378 typedef struct {
379 enum {OnProgress, OnDataAvailable} callback;
380 } URLMON_CallbackData;
383 #if 0
384 static LRESULT CALLBACK URLMON_WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
386 return DefWindowProcA(hwnd, msg, wparam, lparam);
389 static void PostOnProgress(URLMonikerImpl *This, UINT progress, UINT maxprogress, DWORD status, LPCWSTR *str)
393 static void CALLBACK URLMON_InternetCallback(HINTERNET hinet, /*DWORD_PTR*/ DWORD context, DWORD status,
394 void *status_info, DWORD status_info_len)
396 URLMonikerImpl *This = (URLMonikerImpl *)context;
397 TRACE("handle %p this %p status %08lx\n", hinet, This, status);
399 if(This->filesize == -1) {
400 switch(status) {
401 case INTERNET_STATUS_RESOLVING_NAME:
402 PostOnProgess(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, status_info);
403 break;
404 case INTERNET_STATUS_CONNECTING_TO_SERVER:
405 PostOnProgress(This, 0, 0, BINDSTATUS_CONNECTING, NULL);
406 break;
407 case INTERNET_STATUS_SENDING_REQUEST:
408 PostOnProgress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL);
409 break;
410 case INTERNET_REQUEST_COMPLETE:
412 DWORD len, lensz = sizeof(len);
414 HttpQueryInfoW(hrequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &len, &lensz, NULL);
415 TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), len);
416 This->filesize = len;
417 break;
422 return;
424 #endif
427 /******************************************************************************
428 * URLMoniker_BindToStorage
429 ******************************************************************************/
430 static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface,
431 IBindCtx* pbc,
432 IMoniker* pmkToLeft,
433 REFIID riid,
434 VOID** ppvObject)
436 URLMonikerImpl *This = (URLMonikerImpl *)iface;
437 HRESULT hres;
438 BINDINFO bi;
439 DWORD bindf;
440 WCHAR szFileName[MAX_PATH + 1];
442 if(pmkToLeft) {
443 FIXME("pmkToLeft != NULL\n");
444 return E_NOTIMPL;
446 if(!IsEqualIID(&IID_IStream, riid)) {
447 FIXME("unsupported iid\n");
448 return E_NOTIMPL;
451 hres = UMCreateStreamOnCacheFile(This->URLName, 0, szFileName, &This->hCacheFile, &This->pstrCache);
453 if(SUCCEEDED(hres)) {
454 TRACE("Created stream...\n");
456 *ppvObject = (void *) This->pstrCache;
457 IStream_AddRef((IStream *) This->pstrCache);
459 hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&This->pbscb);
460 if(SUCCEEDED(hres)) {
461 TRACE("Got IBindStatusCallback...\n");
463 memset(&bi, 0, sizeof(bi));
464 bi.cbSize = sizeof(bi);
465 bindf = 0;
466 hres = IBindStatusCallback_GetBindInfo(This->pbscb, &bindf, &bi);
467 if(SUCCEEDED(hres)) {
468 WCHAR *urlcopy, *tmpwc;
469 URL_COMPONENTSW url;
470 WCHAR *host, *path, *user, *pass;
471 DWORD lensz = sizeof(This->expected_size);
472 DWORD dwService = 0;
473 BOOL bSuccess;
475 TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n",
476 bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid));
477 hres = IBindStatusCallback_OnStartBinding(This->pbscb, 0, (IBinding*)&This->lpvtbl2);
478 TRACE("OnStartBinding rets %08lx\n", hres);
480 /* This class will accept URLs with the backslash in them. But InternetCrackURL will not - it
481 * requires forward slashes (this is the behaviour of Microsoft's INETAPI). So we need to make
482 * a copy of the URL here and change the backslash to a forward slash everywhere it appears -
483 * but only before any '#' or '?', after which backslash should be left alone.
485 urlcopy = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(This->URLName) + 1));
486 lstrcpyW(urlcopy, This->URLName);
487 for (tmpwc = urlcopy; *tmpwc && *tmpwc != '#' && *tmpwc != '?'; ++tmpwc)
488 if (*tmpwc == '\\')
489 *tmpwc = '/';
491 #if 0
492 if(!registered_wndclass) {
493 WNDCLASSA urlmon_wndclass = {0, URLMON_WndProc,0, 0, URLMON_hInstance, 0, 0, 0, NULL, "URLMON_Callback_Window_Class"};
494 RegisterClassA(&urlmon_wndclass);
495 registered_wndclass = TRUE;
498 This->hwndCallback = CreateWindowA("URLMON_Callback_Window_Class", NULL, 0, 0, 0, 0, 0, 0, 0,
499 URLMON_hInstance, NULL);
501 #endif
502 This->expected_size = 0;
503 This->total_read = 0;
505 memset(&url, 0, sizeof(url));
506 url.dwStructSize = sizeof(url);
507 url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = url.dwUserNameLength = url.dwPasswordLength = 1;
508 InternetCrackUrlW(urlcopy, 0, 0, &url);
509 host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR));
510 memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));
511 host[url.dwHostNameLength] = '\0';
512 path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR));
513 memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));
514 path[url.dwUrlPathLength] = '\0';
515 if (url.dwUserNameLength)
517 user = HeapAlloc(GetProcessHeap(), 0, ((url.dwUserNameLength + 1) * sizeof(WCHAR)));
518 memcpy(user, url.lpszUserName, url.dwUserNameLength * sizeof(WCHAR));
519 user[url.dwUserNameLength] = 0;
521 else
523 user = 0;
525 if (url.dwPasswordLength)
527 pass = HeapAlloc(GetProcessHeap(), 0, ((url.dwPasswordLength + 1) * sizeof(WCHAR)));
528 memcpy(pass, url.lpszPassword, url.dwPasswordLength * sizeof(WCHAR));
529 pass[url.dwPasswordLength] = 0;
531 else
533 pass = 0;
536 switch ((DWORD) url.nScheme)
538 case INTERNET_SCHEME_FTP:
539 case INTERNET_SCHEME_GOPHER:
540 case INTERNET_SCHEME_HTTP:
541 case INTERNET_SCHEME_HTTPS:
543 This->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/);
544 /* InternetSetStatusCallback(This->hinternet, URLMON_InternetCallback);*/
545 if (!This->hinternet)
547 hres = HRESULT_FROM_WIN32(GetLastError());
548 break;
551 switch ((DWORD) url.nScheme)
553 case INTERNET_SCHEME_FTP:
554 if (!url.nPort)
555 url.nPort = INTERNET_DEFAULT_FTP_PORT;
556 dwService = INTERNET_SERVICE_FTP;
557 break;
559 case INTERNET_SCHEME_GOPHER:
560 if (!url.nPort)
561 url.nPort = INTERNET_DEFAULT_GOPHER_PORT;
562 dwService = INTERNET_SERVICE_GOPHER;
563 break;
565 case INTERNET_SCHEME_HTTP:
566 if (!url.nPort)
567 url.nPort = INTERNET_DEFAULT_HTTP_PORT;
568 dwService = INTERNET_SERVICE_HTTP;
569 break;
571 case INTERNET_SCHEME_HTTPS:
572 if (!url.nPort)
573 url.nPort = INTERNET_DEFAULT_HTTPS_PORT;
574 dwService = INTERNET_SERVICE_HTTP;
575 break;
578 This->hconnect = InternetConnectW(This->hinternet, host, url.nPort, user, pass,
579 dwService, 0, (DWORD)This);
580 if (!This->hconnect)
582 hres = HRESULT_FROM_WIN32(GetLastError());
583 CloseHandle(This->hinternet);
584 break;
587 hres = IBindStatusCallback_OnProgress(This->pbscb, 0, 0, 0x22, NULL);
588 hres = IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL);
589 hres = IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL);
590 hres = IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL);
592 bSuccess = FALSE;
594 switch (dwService)
596 case INTERNET_SERVICE_GOPHER:
597 This->hrequest = GopherOpenFileW(This->hconnect,
598 path,
600 INTERNET_FLAG_RELOAD,
602 if (This->hrequest)
603 bSuccess = TRUE;
604 else
605 hres = HRESULT_FROM_WIN32(GetLastError());
606 break;
608 case INTERNET_SERVICE_FTP:
609 This->hrequest = FtpOpenFileW(This->hconnect,
610 path,
611 GENERIC_READ,
612 FTP_TRANSFER_TYPE_BINARY |
613 INTERNET_FLAG_TRANSFER_BINARY |
614 INTERNET_FLAG_RELOAD,
616 if (This->hrequest)
617 bSuccess = TRUE;
618 else
619 hres = HRESULT_FROM_WIN32(GetLastError());
620 break;
622 case INTERNET_SERVICE_HTTP:
623 This->hrequest = HttpOpenRequestW(This->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)This);
624 if (!This->hrequest)
626 hres = HRESULT_FROM_WIN32(GetLastError());
628 else if (!HttpSendRequestW(This->hrequest, NULL, 0, NULL, 0))
630 hres = HRESULT_FROM_WIN32(GetLastError());
631 InternetCloseHandle(This->hrequest);
633 else
635 HttpQueryInfoW(This->hrequest,
636 HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
637 &This->expected_size,
638 &lensz,
639 NULL);
640 bSuccess = TRUE;
642 break;
644 if(bSuccess)
646 TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), This->expected_size);
648 IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName);
650 while(1) {
651 char buf[4096];
652 DWORD bufread;
653 if(InternetReadFile(This->hrequest, buf, sizeof(buf), &bufread)) {
654 TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10));
655 if(bufread == 0) break;
656 hres = URLMonikerImpl_MoreCacheData(This, buf, bufread);
657 } else
658 break;
660 InternetCloseHandle(This->hrequest);
661 hres = S_OK;
664 InternetCloseHandle(This->hconnect);
665 InternetCloseHandle(This->hinternet);
666 break;
668 case INTERNET_SCHEME_FILE:
669 path = This->URLName + 5; /* Skip the "file:" part */
670 if ((path[0] != '/' && path[0] != '\\') ||
671 (path[1] != '/' && path[1] != '\\'))
673 hres = E_FAIL;
675 else
677 HANDLE h;
679 path += 2;
680 if (path[0] == '/' || path[0] == '\\')
681 ++path;
682 h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
683 if (h == (HANDLE) HFILE_ERROR)
685 hres = HRESULT_FROM_WIN32(GetLastError());
687 else
689 char buf[4096];
690 DWORD bufread;
692 IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName);
694 while (ReadFile(h, buf, sizeof(buf), &bufread, NULL) && bufread > 0)
695 hres = URLMonikerImpl_MoreCacheData(This, buf, bufread);
697 CloseHandle(h);
698 hres = S_OK;
702 break;
704 default:
705 FIXME("Unsupported URI scheme");
706 break;
708 URLMonikerImpl_CloseCacheDownload(This);
709 URLMonikerImpl_FinishedDownload(This, hres);
711 if (user)
712 HeapFree(GetProcessHeap(), 0, user);
713 if (pass)
714 HeapFree(GetProcessHeap(), 0, pass);
715 HeapFree(GetProcessHeap(), 0, path);
716 HeapFree(GetProcessHeap(), 0, host);
717 HeapFree(GetProcessHeap(), 0, urlcopy);
721 return hres;
724 /******************************************************************************
725 * URLMoniker_Reduce
726 ******************************************************************************/
727 static HRESULT WINAPI URLMonikerImpl_Reduce(IMoniker* iface,
728 IBindCtx* pbc,
729 DWORD dwReduceHowFar,
730 IMoniker** ppmkToLeft,
731 IMoniker** ppmkReduced)
733 URLMonikerImpl *This = (URLMonikerImpl *)iface;
735 TRACE("(%p,%p,%ld,%p,%p)\n",This,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
737 if(!ppmkReduced)
738 return E_INVALIDARG;
740 URLMonikerImpl_AddRef(iface);
741 *ppmkReduced = iface;
742 return MK_S_REDUCED_TO_SELF;
745 /******************************************************************************
746 * URLMoniker_ComposeWith
747 ******************************************************************************/
748 static HRESULT WINAPI URLMonikerImpl_ComposeWith(IMoniker* iface,
749 IMoniker* pmkRight,
750 BOOL fOnlyIfNotGeneric,
751 IMoniker** ppmkComposite)
753 URLMonikerImpl *This = (URLMonikerImpl *)iface;
754 FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
756 return E_NOTIMPL;
759 /******************************************************************************
760 * URLMoniker_Enum
761 ******************************************************************************/
762 static HRESULT WINAPI URLMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
764 URLMonikerImpl *This = (URLMonikerImpl *)iface;
765 TRACE("(%p,%d,%p)\n",This,fForward,ppenumMoniker);
767 if(!ppenumMoniker)
768 return E_INVALIDARG;
770 /* Does not support sub-monikers */
771 *ppenumMoniker = NULL;
772 return S_OK;
775 /******************************************************************************
776 * URLMoniker_IsEqual
777 ******************************************************************************/
778 static HRESULT WINAPI URLMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
780 URLMonikerImpl *This = (URLMonikerImpl *)iface;
781 CLSID clsid;
782 LPOLESTR urlPath;
783 IBindCtx* bind;
784 HRESULT res;
786 TRACE("(%p,%p)\n",This,pmkOtherMoniker);
788 if(pmkOtherMoniker==NULL)
789 return E_INVALIDARG;
791 IMoniker_GetClassID(pmkOtherMoniker,&clsid);
793 if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker))
794 return S_FALSE;
796 res = CreateBindCtx(0,&bind);
797 if(FAILED(res))
798 return res;
800 res = S_FALSE;
801 if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) {
802 int result = lstrcmpiW(urlPath, This->URLName);
803 CoTaskMemFree(urlPath);
804 if(result == 0)
805 res = S_OK;
807 IUnknown_Release(bind);
808 return res;
812 /******************************************************************************
813 * URLMoniker_Hash
814 ******************************************************************************/
815 static HRESULT WINAPI URLMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
817 URLMonikerImpl *This = (URLMonikerImpl *)iface;
819 int h = 0,i,skip,len;
820 int off = 0;
821 LPOLESTR val;
823 TRACE("(%p,%p)\n",This,pdwHash);
825 if(!pdwHash)
826 return E_INVALIDARG;
828 val = This->URLName;
829 len = lstrlenW(val);
831 if(len < 16) {
832 for(i = len ; i > 0; i--) {
833 h = (h * 37) + val[off++];
836 else {
837 /* only sample some characters */
838 skip = len / 8;
839 for(i = len; i > 0; i -= skip, off += skip) {
840 h = (h * 39) + val[off];
843 *pdwHash = h;
844 return S_OK;
847 /******************************************************************************
848 * URLMoniker_IsRunning
849 ******************************************************************************/
850 static HRESULT WINAPI URLMonikerImpl_IsRunning(IMoniker* iface,
851 IBindCtx* pbc,
852 IMoniker* pmkToLeft,
853 IMoniker* pmkNewlyRunning)
855 URLMonikerImpl *This = (URLMonikerImpl *)iface;
856 FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning);
858 return E_NOTIMPL;
861 /******************************************************************************
862 * URLMoniker_GetTimeOfLastChange
863 ******************************************************************************/
864 static HRESULT WINAPI URLMonikerImpl_GetTimeOfLastChange(IMoniker* iface,
865 IBindCtx* pbc,
866 IMoniker* pmkToLeft,
867 FILETIME* pFileTime)
869 URLMonikerImpl *This = (URLMonikerImpl *)iface;
870 FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pFileTime);
872 return E_NOTIMPL;
875 /******************************************************************************
876 * URLMoniker_Inverse
877 ******************************************************************************/
878 static HRESULT WINAPI URLMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
880 URLMonikerImpl *This = (URLMonikerImpl *)iface;
881 TRACE("(%p,%p)\n",This,ppmk);
883 return MK_E_NOINVERSE;
886 /******************************************************************************
887 * URLMoniker_CommonPrefixWith
888 ******************************************************************************/
889 static HRESULT WINAPI URLMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
891 URLMonikerImpl *This = (URLMonikerImpl *)iface;
892 FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix);
894 return E_NOTIMPL;
897 /******************************************************************************
898 * URLMoniker_RelativePathTo
899 ******************************************************************************/
900 static HRESULT WINAPI URLMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
902 URLMonikerImpl *This = (URLMonikerImpl *)iface;
903 FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath);
905 return E_NOTIMPL;
908 /******************************************************************************
909 * URLMoniker_GetDisplayName
910 ******************************************************************************/
911 static HRESULT WINAPI URLMonikerImpl_GetDisplayName(IMoniker* iface,
912 IBindCtx* pbc,
913 IMoniker* pmkToLeft,
914 LPOLESTR *ppszDisplayName)
916 URLMonikerImpl *This = (URLMonikerImpl *)iface;
918 int len;
920 TRACE("(%p,%p,%p,%p)\n",This,pbc,pmkToLeft,ppszDisplayName);
922 if(!ppszDisplayName)
923 return E_INVALIDARG;
925 /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context,
926 then look at pmkToLeft to try and complete the URL
928 len = lstrlenW(This->URLName)+1;
929 *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR));
930 if(!*ppszDisplayName)
931 return E_OUTOFMEMORY;
932 lstrcpyW(*ppszDisplayName, This->URLName);
933 return S_OK;
936 /******************************************************************************
937 * URLMoniker_ParseDisplayName
938 ******************************************************************************/
939 static HRESULT WINAPI URLMonikerImpl_ParseDisplayName(IMoniker* iface,
940 IBindCtx* pbc,
941 IMoniker* pmkToLeft,
942 LPOLESTR pszDisplayName,
943 ULONG* pchEaten,
944 IMoniker** ppmkOut)
946 URLMonikerImpl *This = (URLMonikerImpl *)iface;
947 FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
949 return E_NOTIMPL;
952 /******************************************************************************
953 * URLMoniker_IsSystemMoniker
954 ******************************************************************************/
955 static HRESULT WINAPI URLMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
957 URLMonikerImpl *This = (URLMonikerImpl *)iface;
958 TRACE("(%p,%p)\n",This,pwdMksys);
960 if(!pwdMksys)
961 return E_INVALIDARG;
963 *pwdMksys = MKSYS_URLMONIKER;
964 return S_OK;
967 static HRESULT WINAPI URLMonikerImpl_IBinding_QueryInterface(IBinding* iface,REFIID riid,void** ppvObject)
969 ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);
971 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
973 /* Perform a sanity check on the parameters.*/
974 if ( (This==0) || (ppvObject==0) )
975 return E_INVALIDARG;
977 /* Initialize the return parameter */
978 *ppvObject = 0;
980 /* Compare the riid with the interface IDs implemented by this object.*/
981 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IBinding, riid))
982 *ppvObject = iface;
984 /* Check that we obtained an interface.*/
985 if ((*ppvObject)==0)
986 return E_NOINTERFACE;
988 /* Query Interface always increases the reference count by one when it is successful */
989 IBinding_AddRef(iface);
991 return S_OK;
995 static ULONG WINAPI URLMonikerImpl_IBinding_AddRef(IBinding* iface)
997 ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);
998 TRACE("(%p)\n",This);
1000 return URLMonikerImpl_AddRef((IMoniker*)This);
1003 static ULONG WINAPI URLMonikerImpl_IBinding_Release(IBinding* iface)
1005 ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);
1006 TRACE("(%p)\n",This);
1008 return URLMonikerImpl_Release((IMoniker*)This);
1011 static HRESULT WINAPI URLMonikerImpl_IBinding_Abort(IBinding* iface)
1013 ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);
1014 FIXME("(%p): stub\n", This);
1016 return E_NOTIMPL;
1019 static HRESULT WINAPI URLMonikerImpl_IBinding_GetBindResult(IBinding* iface, CLSID* pclsidProtocol, DWORD* pdwResult, LPOLESTR* pszResult, DWORD* pdwReserved)
1021 ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);
1022 FIXME("(%p)->(%p, %p, %p, %p): stub\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
1024 return E_NOTIMPL;
1027 static HRESULT WINAPI URLMonikerImpl_IBinding_GetPriority(IBinding* iface, LONG* pnPriority)
1029 ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);
1030 FIXME("(%p)->(%p): stub\n", This, pnPriority);
1032 return E_NOTIMPL;
1035 static HRESULT WINAPI URLMonikerImpl_IBinding_Resume(IBinding* iface)
1037 ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);
1038 FIXME("(%p): stub\n", This);
1040 return E_NOTIMPL;
1043 static HRESULT WINAPI URLMonikerImpl_IBinding_SetPriority(IBinding* iface, LONG nPriority)
1045 ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);
1046 FIXME("(%p)->(%ld): stub\n", This, nPriority);
1048 return E_NOTIMPL;
1051 static HRESULT WINAPI URLMonikerImpl_IBinding_Suspend(IBinding* iface)
1053 ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);
1054 FIXME("(%p): stub\n", This);
1056 return E_NOTIMPL;
1059 /********************************************************************************/
1060 /* Virtual function table for the URLMonikerImpl class which include IPersist,*/
1061 /* IPersistStream and IMoniker functions. */
1062 static IMonikerVtbl VT_URLMonikerImpl =
1064 URLMonikerImpl_QueryInterface,
1065 URLMonikerImpl_AddRef,
1066 URLMonikerImpl_Release,
1067 URLMonikerImpl_GetClassID,
1068 URLMonikerImpl_IsDirty,
1069 URLMonikerImpl_Load,
1070 URLMonikerImpl_Save,
1071 URLMonikerImpl_GetSizeMax,
1072 URLMonikerImpl_BindToObject,
1073 URLMonikerImpl_BindToStorage,
1074 URLMonikerImpl_Reduce,
1075 URLMonikerImpl_ComposeWith,
1076 URLMonikerImpl_Enum,
1077 URLMonikerImpl_IsEqual,
1078 URLMonikerImpl_Hash,
1079 URLMonikerImpl_IsRunning,
1080 URLMonikerImpl_GetTimeOfLastChange,
1081 URLMonikerImpl_Inverse,
1082 URLMonikerImpl_CommonPrefixWith,
1083 URLMonikerImpl_RelativePathTo,
1084 URLMonikerImpl_GetDisplayName,
1085 URLMonikerImpl_ParseDisplayName,
1086 URLMonikerImpl_IsSystemMoniker
1089 static IBindingVtbl VTBinding_URLMonikerImpl =
1091 URLMonikerImpl_IBinding_QueryInterface,
1092 URLMonikerImpl_IBinding_AddRef,
1093 URLMonikerImpl_IBinding_Release,
1094 URLMonikerImpl_IBinding_Abort,
1095 URLMonikerImpl_IBinding_Suspend,
1096 URLMonikerImpl_IBinding_Resume,
1097 URLMonikerImpl_IBinding_SetPriority,
1098 URLMonikerImpl_IBinding_GetPriority,
1099 URLMonikerImpl_IBinding_GetBindResult
1102 /******************************************************************************
1103 * URLMoniker_Construct (local function)
1104 *******************************************************************************/
1105 static HRESULT URLMonikerImpl_Construct(URLMonikerImpl* This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName)
1107 HRESULT hres;
1108 DWORD sizeStr;
1110 TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName));
1111 memset(This, 0, sizeof(*This));
1113 /* Initialize the virtual function table. */
1114 This->lpvtbl1 = &VT_URLMonikerImpl;
1115 This->lpvtbl2 = &VTBinding_URLMonikerImpl;
1116 This->ref = 0;
1118 if(lpszLeftURLName) {
1119 hres = UrlCombineW(lpszLeftURLName, lpszURLName, NULL, &sizeStr, 0);
1120 if(FAILED(hres)) {
1121 return hres;
1123 sizeStr++;
1125 else
1126 sizeStr = lstrlenW(lpszURLName)+1;
1128 This->URLName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr));
1130 if (This->URLName==NULL)
1131 return E_OUTOFMEMORY;
1133 if(lpszLeftURLName) {
1134 hres = UrlCombineW(lpszLeftURLName, lpszURLName, This->URLName, &sizeStr, 0);
1135 if(FAILED(hres)) {
1136 HeapFree(GetProcessHeap(), 0, This->URLName);
1137 return hres;
1140 else
1141 strcpyW(This->URLName,lpszURLName);
1143 return S_OK;
1146 /***********************************************************************
1147 * CreateAsyncBindCtx (URLMON.@)
1149 HRESULT WINAPI CreateAsyncBindCtx(DWORD reserved, IBindStatusCallback *callback,
1150 IEnumFORMATETC *format, IBindCtx **pbind)
1152 HRESULT hres;
1153 BIND_OPTS bindopts;
1154 IBindCtx *bctx;
1156 TRACE("(%08lx %p %p %p)\n", reserved, callback, format, pbind);
1158 if(!callback)
1159 return E_INVALIDARG;
1160 if(format)
1161 FIXME("format is not supported yet\n");
1163 hres = CreateBindCtx(0, &bctx);
1164 if(FAILED(hres))
1165 return hres;
1167 bindopts.cbStruct = sizeof(BIND_OPTS);
1168 bindopts.grfFlags = BIND_MAYBOTHERUSER;
1169 bindopts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
1170 bindopts.dwTickCountDeadline = 0;
1171 IBindCtx_SetBindOptions(bctx, &bindopts);
1173 hres = IBindCtx_RegisterObjectParam(bctx, (LPOLESTR)BSCBHolder, (IUnknown*)callback);
1174 if(FAILED(hres)) {
1175 IBindCtx_Release(bctx);
1176 return hres;
1179 *pbind = bctx;
1181 return S_OK;
1183 /***********************************************************************
1184 * CreateAsyncBindCtxEx (URLMON.@)
1186 * Create an asynchronous bind context.
1188 * FIXME
1189 * Not implemented.
1191 HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options,
1192 IBindStatusCallback *callback, IEnumFORMATETC *format, IBindCtx** pbind,
1193 DWORD reserved)
1195 FIXME("stub, returns failure\n");
1196 return E_INVALIDARG;
1200 /***********************************************************************
1201 * CreateURLMoniker (URLMON.@)
1203 * Create a url moniker.
1205 * PARAMS
1206 * pmkContext [I] Context
1207 * szURL [I] Url to create the moniker for
1208 * ppmk [O] Destination for created moniker.
1210 * RETURNS
1211 * Success: S_OK. ppmk contains the created IMoniker object.
1212 * Failure: MK_E_SYNTAX if szURL is not a valid url, or
1213 * E_OUTOFMEMORY if memory allocation fails.
1215 HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk)
1217 URLMonikerImpl *obj;
1218 HRESULT hres;
1219 IID iid = IID_IMoniker;
1220 LPOLESTR lefturl = NULL;
1222 TRACE("(%p, %s, %p)\n", pmkContext, debugstr_w(szURL), ppmk);
1224 if(!(obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj))))
1225 return E_OUTOFMEMORY;
1227 if(pmkContext) {
1228 CLSID clsid;
1229 IBindCtx* bind;
1230 IMoniker_GetClassID(pmkContext, &clsid);
1231 if(IsEqualCLSID(&clsid, &CLSID_StdURLMoniker) && SUCCEEDED(CreateBindCtx(0, &bind))) {
1232 URLMonikerImpl_GetDisplayName(pmkContext, bind, NULL, &lefturl);
1233 IBindCtx_Release(bind);
1237 hres = URLMonikerImpl_Construct(obj, lefturl, szURL);
1238 CoTaskMemFree(lefturl);
1239 if(SUCCEEDED(hres))
1240 hres = URLMonikerImpl_QueryInterface((IMoniker*)obj, &iid, (void**)ppmk);
1241 else
1242 HeapFree(GetProcessHeap(), 0, obj);
1243 return hres;
1247 /***********************************************************************
1248 * CoInternetGetSession (URLMON.@)
1250 * Create a new internet session and return an IInternetSession interface
1251 * representing it.
1253 * PARAMS
1254 * dwSessionMode [I] Mode for the internet session
1255 * ppIInternetSession [O] Destination for creates IInternetSession object
1256 * dwReserved [I] Reserved, must be 0.
1258 * RETURNS
1259 * Success: S_OK. ppIInternetSession contains the IInternetSession interface.
1260 * Failure: E_INVALIDARG, if any argument is invalid, or
1261 * E_OUTOFMEMORY if memory allocation fails.
1263 HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession, DWORD dwReserved)
1265 FIXME("(%ld, %p, %ld): stub\n", dwSessionMode, ppIInternetSession, dwReserved);
1267 if(dwSessionMode) {
1268 ERR("dwSessionMode: %ld, must be zero\n", dwSessionMode);
1271 if(dwReserved) {
1272 ERR("dwReserved: %ld, must be zero\n", dwReserved);
1275 *ppIInternetSession=NULL;
1276 return E_OUTOFMEMORY;
1279 /***********************************************************************
1280 * CoInternetQueryInfo (URLMON.@)
1282 * Retrieves information relevant to a specified URL
1284 * RETURNS
1285 * S_OK success
1286 * S_FALSE buffer too small
1287 * INET_E_QUERYOPTIONUNKNOWN invalid option
1290 HRESULT WINAPI CoInternetQueryInfo(LPCWSTR pwzUrl, QUERYOPTION QueryOption,
1291 DWORD dwQueryFlags, LPVOID pvBuffer, DWORD cbBuffer, DWORD * pcbBuffer,
1292 DWORD dwReserved)
1294 FIXME("(%s, %x, %lx, %p, %lx, %p, %lx): stub\n", debugstr_w(pwzUrl),
1295 QueryOption, dwQueryFlags, pvBuffer, cbBuffer, pcbBuffer, dwReserved);
1296 return S_OK;
1299 static BOOL URLMON_IsBinary(LPVOID pBuffer, DWORD cbSize)
1301 unsigned int i, binarycount = 0;
1302 unsigned char *buff = pBuffer;
1303 for(i=0; i<cbSize; i++) {
1304 if(buff[i] < 32)
1305 binarycount++;
1307 return binarycount > (cbSize-binarycount);
1310 /***********************************************************************
1311 * FindMimeFromData (URLMON.@)
1313 * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided.
1315 * NOTE
1316 * See http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp
1318 HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer,
1319 DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags,
1320 LPWSTR* ppwzMimeOut, DWORD dwReserved)
1322 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'};
1323 static const WCHAR szTextMime[] = {'t','e','x','t','/','p','l','a','i','n','\0'};
1324 static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'};
1325 WCHAR szTmpMime[256];
1326 LPCWSTR mimeType = NULL;
1327 HKEY hKey = NULL;
1329 TRACE("(%p,%s,%p,%ld,%s,0x%lx,%p,0x%lx)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize,
1330 debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved);
1332 if((!pwzUrl && (!pBuffer || cbSize <= 0)) || !ppwzMimeOut)
1333 return E_INVALIDARG;
1335 if(pwzMimeProposed)
1336 mimeType = pwzMimeProposed;
1337 else {
1338 /* Try and find the mime type in the registry */
1339 if(pwzUrl) {
1340 LPWSTR ext = strrchrW(pwzUrl, '.');
1341 if(ext) {
1342 DWORD dwSize;
1343 if(!RegOpenKeyExW(HKEY_CLASSES_ROOT, ext, 0, 0, &hKey)) {
1344 if(!RegQueryValueExW(hKey, szContentType, NULL, NULL, (LPBYTE)szTmpMime, &dwSize)) {
1345 mimeType = szTmpMime;
1347 RegCloseKey(hKey);
1352 if(!mimeType && pBuffer && cbSize > 0)
1353 mimeType = URLMON_IsBinary(pBuffer, cbSize)?szBinaryMime:szTextMime;
1355 TRACE("Using %s\n", debugstr_w(mimeType));
1356 *ppwzMimeOut = CoTaskMemAlloc((lstrlenW(mimeType)+1)*sizeof(WCHAR));
1357 if(!*ppwzMimeOut) return E_OUTOFMEMORY;
1358 lstrcpyW(*ppwzMimeOut, mimeType);
1359 return S_OK;
1362 /***********************************************************************
1363 * IsAsyncMoniker (URLMON.@)
1365 HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk)
1367 IUnknown *am;
1369 TRACE("(%p)\n", pmk);
1370 if(!pmk)
1371 return E_INVALIDARG;
1372 if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) {
1373 IUnknown_Release(am);
1374 return S_OK;
1376 return S_FALSE;
1379 /***********************************************************************
1380 * RegisterBindStatusCallback (URLMON.@)
1382 * Register a bind status callback.
1384 * PARAMS
1385 * pbc [I] Binding context
1386 * pbsc [I] Callback to register
1387 * ppbscPrevious [O] Destination for previous callback
1388 * dwReserved [I] Reserved, must be 0.
1390 * RETURNS
1391 * Success: S_OK.
1392 * Failure: E_INVALIDARG, if any argument is invalid, or
1393 * E_OUTOFMEMORY if memory allocation fails.
1395 HRESULT WINAPI RegisterBindStatusCallback(
1396 IBindCtx *pbc,
1397 IBindStatusCallback *pbsc,
1398 IBindStatusCallback **ppbscPrevious,
1399 DWORD dwReserved)
1401 IBindStatusCallback *prev;
1403 TRACE("(%p,%p,%p,%lu)\n", pbc, pbsc, ppbscPrevious, dwReserved);
1405 if (pbc == NULL || pbsc == NULL)
1406 return E_INVALIDARG;
1408 if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&prev)))
1410 IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder);
1411 if (ppbscPrevious)
1412 *ppbscPrevious = prev;
1413 else
1414 IBindStatusCallback_Release(prev);
1417 return IBindCtx_RegisterObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown *)pbsc);
1420 /***********************************************************************
1421 * RevokeBindStatusCallback (URLMON.@)
1423 * Unregister a bind status callback.
1425 * pbc [I] Binding context
1426 * pbsc [I] Callback to unregister
1428 * RETURNS
1429 * Success: S_OK.
1430 * Failure: E_INVALIDARG, if any argument is invalid, or
1431 * E_FAIL if pbsc wasn't registered with pbc.
1433 HRESULT WINAPI RevokeBindStatusCallback(
1434 IBindCtx *pbc,
1435 IBindStatusCallback *pbsc)
1437 IBindStatusCallback *callback;
1438 HRESULT hr = E_FAIL;
1440 TRACE("(%p,%p)\n", pbc, pbsc);
1442 if (pbc == NULL || pbsc == NULL)
1443 return E_INVALIDARG;
1445 if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&callback)))
1447 if (callback == pbsc)
1449 IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder);
1450 hr = S_OK;
1452 IBindStatusCallback_Release(pbsc);
1455 return hr;
1458 /***********************************************************************
1459 * ReleaseBindInfo (URLMON.@)
1461 * Release the resources used by the specified BINDINFO structure.
1463 * PARAMS
1464 * pbindinfo [I] BINDINFO to release.
1466 * RETURNS
1467 * Nothing.
1469 void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo)
1471 FIXME("(%p)stub!\n", pbindinfo);
1474 /***********************************************************************
1475 * URLDownloadToFileA (URLMON.@)
1477 * Downloads URL szURL to rile szFileName and call lpfnCB callback to
1478 * report progress.
1480 * PARAMS
1481 * pCaller [I] controlling IUnknown interface.
1482 * szURL [I] URL of the file to download
1483 * szFileName [I] file name to store the content of the URL
1484 * dwReserved [I] reserved - set to 0
1485 * lpfnCB [I] callback for progress report
1487 * RETURNS
1488 * S_OK on success
1489 * E_OUTOFMEMORY when going out of memory
1491 HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller,
1492 LPCSTR szURL,
1493 LPCSTR szFileName,
1494 DWORD dwReserved,
1495 LPBINDSTATUSCALLBACK lpfnCB)
1497 UNICODE_STRING szURL_w, szFileName_w;
1499 if ((szURL == NULL) || (szFileName == NULL)) {
1500 FIXME("(%p,%s,%s,%08lx,%p) cannot accept NULL strings !\n", pCaller, debugstr_a(szURL), debugstr_a(szFileName), dwReserved, lpfnCB);
1501 return E_INVALIDARG; /* The error code is not specified in this case... */
1504 if (RtlCreateUnicodeStringFromAsciiz(&szURL_w, szURL)) {
1505 if (RtlCreateUnicodeStringFromAsciiz(&szFileName_w, szFileName)) {
1506 HRESULT ret = URLDownloadToFileW(pCaller, szURL_w.Buffer, szFileName_w.Buffer, dwReserved, lpfnCB);
1508 RtlFreeUnicodeString(&szURL_w);
1509 RtlFreeUnicodeString(&szFileName_w);
1511 return ret;
1512 } else {
1513 RtlFreeUnicodeString(&szURL_w);
1517 FIXME("(%p,%s,%s,%08lx,%p) could not allocate W strings !\n", pCaller, szURL, szFileName, dwReserved, lpfnCB);
1518 return E_OUTOFMEMORY;
1521 /***********************************************************************
1522 * URLDownloadToFileW (URLMON.@)
1524 * Downloads URL szURL to rile szFileName and call lpfnCB callback to
1525 * report progress.
1527 * PARAMS
1528 * pCaller [I] controlling IUnknown interface.
1529 * szURL [I] URL of the file to download
1530 * szFileName [I] file name to store the content of the URL
1531 * dwReserved [I] reserved - set to 0
1532 * lpfnCB [I] callback for progress report
1534 * RETURNS
1535 * S_OK on success
1536 * E_OUTOFMEMORY when going out of memory
1538 HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller,
1539 LPCWSTR szURL,
1540 LPCWSTR szFileName,
1541 DWORD dwReserved,
1542 LPBINDSTATUSCALLBACK lpfnCB)
1544 HINTERNET hinternet, hcon, hreq;
1545 BOOL r;
1546 CHAR buffer[0x1000];
1547 DWORD sz, total, written;
1548 DWORD total_size = 0xFFFFFFFF, arg_size = sizeof(total_size);
1549 URL_COMPONENTSW url;
1550 WCHAR host[0x80], path[0x100];
1551 HANDLE hfile;
1552 static const WCHAR wszAppName[]={'u','r','l','m','o','n','.','d','l','l',0};
1554 /* Note: all error codes would need to be checked agains real Windows behaviour... */
1555 TRACE("(%p,%s,%s,%08lx,%p) stub!\n", pCaller, debugstr_w(szURL), debugstr_w(szFileName), dwReserved, lpfnCB);
1557 if ((szURL == NULL) || (szFileName == NULL)) {
1558 FIXME(" cannot accept NULL strings !\n");
1559 return E_INVALIDARG;
1562 /* Would be better to use the application name here rather than 'urlmon' :-/ */
1563 hinternet = InternetOpenW(wszAppName, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
1564 if (hinternet == NULL) {
1565 return E_OUTOFMEMORY;
1568 memset(&url, 0, sizeof(url));
1569 url.dwStructSize = sizeof(url);
1570 url.lpszHostName = host;
1571 url.dwHostNameLength = sizeof(host);
1572 url.lpszUrlPath = path;
1573 url.dwUrlPathLength = sizeof(path);
1575 if (!InternetCrackUrlW(szURL, 0, 0, &url)) {
1576 InternetCloseHandle(hinternet);
1577 return E_OUTOFMEMORY;
1580 if (lpfnCB) {
1581 if (IBindStatusCallback_OnProgress(lpfnCB, 0, 0, BINDSTATUS_CONNECTING, url.lpszHostName) == E_ABORT) {
1582 InternetCloseHandle(hinternet);
1583 return S_OK;
1587 hcon = InternetConnectW(hinternet, url.lpszHostName, url.nPort,
1588 url.lpszUserName, url.lpszPassword,
1589 INTERNET_SERVICE_HTTP, 0, 0);
1590 if (!hcon) {
1591 InternetCloseHandle(hinternet);
1592 return E_OUTOFMEMORY;
1595 hreq = HttpOpenRequestW(hcon, NULL, url.lpszUrlPath, NULL, NULL, NULL, 0, 0);
1596 if (!hreq) {
1597 InternetCloseHandle(hinternet);
1598 InternetCloseHandle(hcon);
1599 return E_OUTOFMEMORY;
1602 if (!HttpSendRequestW(hreq, NULL, 0, NULL, 0)) {
1603 InternetCloseHandle(hinternet);
1604 InternetCloseHandle(hcon);
1605 InternetCloseHandle(hreq);
1606 return E_OUTOFMEMORY;
1609 if (HttpQueryInfoW(hreq, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
1610 &total_size, &arg_size, NULL)) {
1611 TRACE(" total size : %ld\n", total_size);
1614 hfile = CreateFileW(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1615 FILE_ATTRIBUTE_NORMAL, NULL );
1616 if (hfile == INVALID_HANDLE_VALUE) {
1617 return E_ACCESSDENIED;
1620 if (lpfnCB) {
1621 if (IBindStatusCallback_OnProgress(lpfnCB, 0, total_size != 0xFFFFFFFF ? total_size : 0,
1622 BINDSTATUS_BEGINDOWNLOADDATA, szURL) == E_ABORT) {
1623 InternetCloseHandle(hreq);
1624 InternetCloseHandle(hcon);
1625 InternetCloseHandle(hinternet);
1626 CloseHandle(hfile);
1627 return S_OK;
1631 total = 0;
1632 while (1) {
1633 r = InternetReadFile(hreq, buffer, sizeof(buffer), &sz);
1634 if (!r) {
1635 InternetCloseHandle(hreq);
1636 InternetCloseHandle(hcon);
1637 InternetCloseHandle(hinternet);
1639 CloseHandle(hfile);
1640 return E_OUTOFMEMORY;
1642 if (!sz)
1643 break;
1645 total += sz;
1647 if (lpfnCB) {
1648 if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0,
1649 BINDSTATUS_DOWNLOADINGDATA, szURL) == E_ABORT) {
1650 InternetCloseHandle(hreq);
1651 InternetCloseHandle(hcon);
1652 InternetCloseHandle(hinternet);
1653 CloseHandle(hfile);
1654 return S_OK;
1658 if (!WriteFile(hfile, buffer, sz, &written, NULL)) {
1659 InternetCloseHandle(hreq);
1660 InternetCloseHandle(hcon);
1661 InternetCloseHandle(hinternet);
1663 CloseHandle(hfile);
1664 return E_OUTOFMEMORY;
1668 if (lpfnCB) {
1669 if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0,
1670 BINDSTATUS_ENDDOWNLOADDATA, szURL) == E_ABORT) {
1671 InternetCloseHandle(hreq);
1672 InternetCloseHandle(hcon);
1673 InternetCloseHandle(hinternet);
1674 CloseHandle(hfile);
1675 return S_OK;
1679 InternetCloseHandle(hreq);
1680 InternetCloseHandle(hcon);
1681 InternetCloseHandle(hinternet);
1683 CloseHandle(hfile);
1685 return S_OK;
1688 /***********************************************************************
1689 * HlinkSimpleNavigateToString (URLMON.@)
1691 HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget,
1692 LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk,
1693 IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved)
1695 FIXME("%s\n", debugstr_w( szTarget ) );
1696 return E_NOTIMPL;
1699 /***********************************************************************
1700 * HlinkNavigateString (URLMON.@)
1702 HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget )
1704 TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) );
1705 return HlinkSimpleNavigateToString(
1706 szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 );