[URLMON] Implement URLDownloadToFileA/W

Lionel Ulmer lionel.ulmer at free.fr
Sun Jul 13 16:30:24 CDT 2003


This is needed by Anarchy Online's web downloader tool. Thanks to Mike to
have given me some Win32 code of his which did about what I needed, I just
had to tidy it up, add the QueryInfo call and the callbacks.

          Lionel

Changelog:
 Mike McCormack <mike at codeweavers.com>
 Lionel Ulmer <lionel.ulmer at free.fr>
 - implement URLDownloadToFileA/W

-- 
		 Lionel Ulmer - http://www.bbrox.org/
-------------- next part --------------
Index: include/urlmon.h
===================================================================
RCS file: /home/wine/wine/include/urlmon.h,v
retrieving revision 1.17
diff -u -r1.17 urlmon.h
--- include/urlmon.h	13 Jun 2003 16:29:36 -0000	1.17
+++ include/urlmon.h	13 Jul 2003 21:27:07 -0000
@@ -312,6 +312,10 @@
 HRESULT WINAPI RegisterBindStatusCallback(IBindCtx *pbc, IBindStatusCallback *pbsc, IBindStatusCallback **ppbsc, DWORD dwReserved);
 HRESULT WINAPI CompareSecurityIds(BYTE*,DWORD,BYTE*,DWORD,DWORD);
 
+HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller, LPCSTR szURL,  LPCSTR  szFileName, DWORD dwReserved, LPBINDSTATUSCALLBACK lpfnCB);
+HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller, LPCWSTR szURL, LPCWSTR szFileName, DWORD dwReserved, LPBINDSTATUSCALLBACK lpfnCB);
+
+
 #ifdef __cplusplus
 }      /* extern "C" */
 #endif /* defined(__cplusplus) */
Index: dlls/urlmon/umon.c
===================================================================
RCS file: /home/wine/wine/dlls/urlmon/umon.c,v
retrieving revision 1.22
diff -u -r1.22 umon.c
--- dlls/urlmon/umon.c	31 Mar 2003 23:58:27 -0000	1.22
+++ dlls/urlmon/umon.c	13 Jul 2003 21:27:08 -0000
@@ -26,6 +26,7 @@
 #define NONAMELESSSTRUCT
 #include "windef.h"
 #include "winbase.h"
+#include "winternl.h"
 #include "winuser.h"
 #include "objbase.h"
 #include "wine/debug.h"
@@ -1013,4 +1014,218 @@
 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;
+    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;
 }
Index: dlls/urlmon/urlmon.spec
===================================================================
RCS file: /home/wine/wine/dlls/urlmon/urlmon.spec,v
retrieving revision 1.24
diff -u -r1.24 urlmon.spec
--- dlls/urlmon/urlmon.spec	13 Jun 2003 16:29:36 -0000	1.24
+++ dlls/urlmon/urlmon.spec	13 Jul 2003 21:27:08 -0000
@@ -61,8 +61,8 @@
 @ stub URLDownloadA
 @ stub URLDownloadToCacheFileA
 @ stub URLDownloadToCacheFileW
-@ stub URLDownloadToFileA
-@ stub URLDownloadToFileW
+@ stdcall URLDownloadToFileA(ptr str str long ptr)
+@ stdcall URLDownloadToFileW(ptr wstr wstr long ptr)
 @ stub URLDownloadW
 @ stub URLOpenBlockingStreamA
 @ stub URLOpenBlockingStreamW


More information about the wine-patches mailing list