\r
/*static BOOL registered_wndclass = FALSE;*/\r
\r
-/* filemoniker data structure */\r
-typedef struct URLMonikerImpl{\r
+typedef struct {\r
+ IBindingVtbl *lpVtbl;\r
\r
- IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/\r
- IBindingVtbl* lpvtbl2; /* VTable to IBinding interface */\r
+ ULONG ref;\r
\r
- ULONG ref; /* reference counter for this object */\r
-\r
- LPOLESTR URLName; /* URL string identified by this URLmoniker */\r
+ LPWSTR URLName;\r
\r
HWND hwndCallback;\r
IBindCtx *pBC;\r
HINTERNET hinternet, hconnect, hrequest;\r
+ HANDLE hCacheFile;\r
+ IUMCacheStream *pstrCache;\r
+ IBindStatusCallback *pbscb;\r
+ DWORD total_read, expected_size;\r
+} Binding;\r
+\r
+static HRESULT WINAPI Binding_QueryInterface(IBinding* iface, REFIID riid, void **ppvObject)\r
+{\r
+ Binding *This = (Binding*)iface;\r
+\r
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppvObject);\r
+\r
+ if((This == NULL) || (ppvObject == NULL))\r
+ return E_INVALIDARG;\r
+\r
+ if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IBinding, riid)) {\r
+ *ppvObject = iface;\r
+ IBinding_AddRef(iface);\r
+ return S_OK;\r
+ }\r
+\r
+ *ppvObject = NULL;\r
+ return E_NOINTERFACE;\r
+}\r
+\r
+static ULONG WINAPI Binding_AddRef(IBinding* iface)\r
+{\r
+ Binding *This = (Binding*)iface;\r
+ ULONG ref = InterlockedIncrement(&This->ref);\r
+\r
+ TRACE("(%p) ref=%ld\n", This, ref);\r
+\r
+ return ref;\r
+}\r
+\r
+static ULONG WINAPI Binding_Release(IBinding* iface)\r
+{\r
+ Binding *This = (Binding*)iface;\r
+ ULONG ref = InterlockedDecrement(&This->ref);\r
+\r
+ TRACE("(%p) ref=%ld\n",This, ref);\r
+\r
+ if(!ref) {\r
+ HeapFree(GetProcessHeap(), 0, This->URLName);\r
+ if (This->hCacheFile)\r
+ CloseHandle(This->hCacheFile);\r
+ if (This->pstrCache)\r
+ {\r
+ UMCloseCacheFileStream(This->pstrCache);\r
+ IStream_Release((IStream *)This->pstrCache);\r
+ }\r
+ if (This->pbscb)\r
+ IBindStatusCallback_Release(This->pbscb);\r
+\r
+ HeapFree(GetProcessHeap(), 0, This);\r
+\r
+ URLMON_UnlockModule();\r
+ }\r
+\r
+ return ref;\r
+}\r
+\r
+static HRESULT WINAPI Binding_Abort(IBinding* iface)\r
+{\r
+ Binding *This = (Binding*)iface;\r
+\r
+ FIXME("(%p): stub\n", This);\r
+\r
+ return E_NOTIMPL;\r
+}\r
+\r
+static HRESULT WINAPI Binding_GetBindResult(IBinding* iface, CLSID* pclsidProtocol, DWORD* pdwResult, LPOLESTR* pszResult, DWORD* pdwReserved)\r
+{\r
+ Binding *This = (Binding*)iface;\r
+\r
+ FIXME("(%p)->(%p, %p, %p, %p): stub\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);\r
+\r
+ return E_NOTIMPL;\r
+}\r
+\r
+static HRESULT WINAPI Binding_GetPriority(IBinding* iface, LONG* pnPriority)\r
+{\r
+ Binding *This = (Binding*)iface;\r
+\r
+ FIXME("(%p)->(%p): stub\n", This, pnPriority);\r
+\r
+ return E_NOTIMPL;\r
+}\r
+\r
+static HRESULT WINAPI Binding_Resume(IBinding* iface)\r
+{\r
+ Binding *This = (Binding*)iface;\r
+\r
+ FIXME("(%p): stub\n", This);\r
+\r
+ return E_NOTIMPL;\r
+}\r
+\r
+static HRESULT WINAPI Binding_SetPriority(IBinding* iface, LONG nPriority)\r
+{\r
+ Binding *This = (Binding*)iface;\r
+\r
+ FIXME("(%p)->(%ld): stub\n", This, nPriority);\r
+\r
+ return E_NOTIMPL;\r
+}\r
+\r
+static HRESULT WINAPI Binding_Suspend(IBinding* iface)\r
+{\r
+ Binding *This = (Binding*)iface;\r
+\r
+ FIXME("(%p): stub\n", This);\r
+\r
+ return E_NOTIMPL;\r
+}\r
+\r
+static void Binding_CloseCacheDownload(Binding *This)\r
+{\r
+ CloseHandle(This->hCacheFile);\r
+ This->hCacheFile = 0;\r
+ UMCloseCacheFileStream(This->pstrCache);\r
+ IStream_Release((IStream *)This->pstrCache);\r
+ This->pstrCache = 0;\r
+}\r
+\r
+static HRESULT Binding_MoreCacheData(Binding *This, char *buf, DWORD dwBytes)\r
+{\r
+ DWORD written;\r
+\r
+ if (WriteFile(This->hCacheFile, buf, dwBytes, &written, NULL) && written == dwBytes)\r
+ {\r
+ HRESULT hr;\r
+\r
+ This->total_read += written;\r
+ hr = IBindStatusCallback_OnProgress(This->pbscb,\r
+ This->total_read + written,\r
+ This->expected_size,\r
+ (This->total_read == written) ?\r
+ BINDSTATUS_BEGINDOWNLOADDATA :\r
+ BINDSTATUS_DOWNLOADINGDATA,\r
+ NULL);\r
+ if (!hr)\r
+ {\r
+ STGMEDIUM stg;\r
+ FORMATETC fmt;\r
+\r
+ fmt.cfFormat = 0;\r
+ fmt.ptd = NULL;\r
+ fmt.dwAspect = 0;\r
+ fmt.lindex = -1;\r
+ fmt.tymed = TYMED_ISTREAM;\r
+\r
+ stg.tymed = TYMED_ISTREAM;\r
+ stg.u.pstm = (IStream *)This->pstrCache;\r
+ stg.pUnkForRelease = NULL;\r
+\r
+ hr = IBindStatusCallback_OnDataAvailable(This->pbscb,\r
+ (This->total_read == written) ?\r
+ BSCF_FIRSTDATANOTIFICATION :\r
+ BSCF_INTERMEDIATEDATANOTIFICATION,\r
+ This->total_read + written,\r
+ &fmt,\r
+ &stg);\r
+ }\r
+ if (written < dwBytes)\r
+ return STG_E_MEDIUMFULL;\r
+ else\r
+ return hr;\r
+ }\r
+ return HRESULT_FROM_WIN32(GetLastError());\r
+}\r
+\r
+static void Binding_FinishedDownload(Binding *This, HRESULT hr)\r
+{\r
+ STGMEDIUM stg;\r
+ FORMATETC fmt;\r
+\r
+ fmt.ptd = NULL;\r
+ fmt.dwAspect = 0;\r
+ fmt.lindex = -1;\r
+ fmt.tymed = TYMED_ISTREAM;\r
+\r
+ stg.tymed = TYMED_ISTREAM;\r
+ stg.u.pstm = (IStream *)This->pstrCache;\r
+ stg.pUnkForRelease = NULL;\r
+\r
+ IBindStatusCallback_OnProgress(This->pbscb, This->total_read, This->expected_size, BINDSTATUS_ENDDOWNLOADDATA, NULL);\r
+ IBindStatusCallback_OnDataAvailable(This->pbscb, BSCF_LASTDATANOTIFICATION, This->total_read, &fmt, &stg);\r
+ if (hr)\r
+ {\r
+ WCHAR *pwchError = 0;\r
+\r
+ FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |\r
+ FORMAT_MESSAGE_ALLOCATE_BUFFER,\r
+ NULL, (DWORD) hr,\r
+ 0, (LPWSTR) &pwchError,\r
+ 0, NULL);\r
+ if (!pwchError)\r
+ {\r
+ static WCHAR achFormat[] = { '%', '0', '8', 'x', 0 };\r
+\r
+ pwchError =(WCHAR *) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * 9);\r
+ wsprintfW(pwchError, achFormat, hr);\r
+ }\r
+ IBindStatusCallback_OnStopBinding(This->pbscb, hr, pwchError);\r
+ LocalFree(pwchError);\r
+ }\r
+ else\r
+ {\r
+ IBindStatusCallback_OnStopBinding(This->pbscb, hr, NULL);\r
+ }\r
+ IBindStatusCallback_Release(This->pbscb);\r
+ This->pbscb = 0;\r
+}\r
+\r
+static IBindingVtbl BindingVtbl =\r
+{\r
+ Binding_QueryInterface,\r
+ Binding_AddRef,\r
+ Binding_Release,\r
+ Binding_Abort,\r
+ Binding_Suspend,\r
+ Binding_Resume,\r
+ Binding_SetPriority,\r
+ Binding_GetPriority,\r
+ Binding_GetBindResult\r
+};\r
+\r
+/* filemoniker data structure */\r
+typedef struct {\r
+\r
+ IMonikerVtbl* lpvtbl; /* VTable relative to the IMoniker interface.*/\r
+\r
+ ULONG ref; /* reference counter for this object */\r
+\r
+ LPOLESTR URLName; /* URL string identified by this URLmoniker */\r
} URLMonikerImpl;\r
\r
/*******************************************************************************\r
return refCount;\r
}\r
\r
+\r
/******************************************************************************\r
* URLMoniker_GetClassID\r
******************************************************************************/\r
return;\r
}\r
#endif\r
+\r
+\r
/******************************************************************************\r
* URLMoniker_BindToStorage\r
******************************************************************************/\r
{\r
URLMonikerImpl *This = (URLMonikerImpl *)iface;\r
HRESULT hres;\r
- IBindStatusCallback *pbscb;\r
BINDINFO bi;\r
DWORD bindf;\r
- IStream *pstr;\r
+ WCHAR szFileName[MAX_PATH + 1];\r
+ Binding *bind;\r
+ int len;\r
\r
- FIXME("(%p)->(%p,%p,%s,%p): stub\n",This,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);\r
if(pmkToLeft) {\r
FIXME("pmkToLeft != NULL\n");\r
return E_NOTIMPL;\r
return E_NOTIMPL;\r
}\r
\r
- /* FIXME This is a bad hack (tm). We should clearly download to a temporary file.\r
- We also need to implement IStream ourselves so that IStream_Read can return\r
- E_PENDING */\r
+ bind = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Binding));\r
+ bind->lpVtbl = &BindingVtbl;\r
+ bind->ref = 1;\r
+ URLMON_LockModule();\r
+\r
+ len = lstrlenW(This->URLName)+1;\r
+ bind->URLName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));\r
+ memcpy(bind->URLName, This->URLName, len*sizeof(WCHAR));\r
\r
- hres = CreateStreamOnHGlobal(0, TRUE, &pstr);\r
+ hres = UMCreateStreamOnCacheFile(bind->URLName, 0, szFileName, &bind->hCacheFile, &bind->pstrCache);\r
\r
if(SUCCEEDED(hres)) {\r
- TRACE("Created dummy stream...\n");\r
+ TRACE("Created stream...\n");\r
+\r
+ *ppvObject = (void *) bind->pstrCache;\r
+ IStream_AddRef((IStream *) bind->pstrCache);\r
\r
- hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&pbscb);\r
+ hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&bind->pbscb);\r
if(SUCCEEDED(hres)) {\r
TRACE("Got IBindStatusCallback...\n");\r
\r
memset(&bi, 0, sizeof(bi));\r
bi.cbSize = sizeof(bi);\r
bindf = 0;\r
- hres = IBindStatusCallback_GetBindInfo(pbscb, &bindf, &bi);\r
+ hres = IBindStatusCallback_GetBindInfo(bind->pbscb, &bindf, &bi);\r
if(SUCCEEDED(hres)) {\r
+ WCHAR *urlcopy, *tmpwc;\r
URL_COMPONENTSW url;\r
- WCHAR *host, *path;\r
- DWORD len, lensz = sizeof(len), total_read = 0;\r
- LARGE_INTEGER last_read_pos;\r
- FORMATETC fmt;\r
- STGMEDIUM stg;\r
+ WCHAR *host, *path, *user, *pass;\r
+ DWORD lensz = sizeof(bind->expected_size);\r
+ DWORD dwService = 0;\r
+ BOOL bSuccess;\r
\r
TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n",\r
bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid));\r
- hres = IBindStatusCallback_OnStartBinding(pbscb, 0, (IBinding*)&This->lpvtbl2);\r
+ hres = IBindStatusCallback_OnStartBinding(bind->pbscb, 0, (IBinding*)bind);\r
TRACE("OnStartBinding rets %08lx\n", hres);\r
\r
+ /* This class will accept URLs with the backslash in them. But InternetCrackURL will not - it\r
+ * requires forward slashes (this is the behaviour of Microsoft's INETAPI). So we need to make\r
+ * a copy of the URL here and change the backslash to a forward slash everywhere it appears -\r
+ * but only before any '#' or '?', after which backslash should be left alone.\r
+ */\r
+ urlcopy = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(bind->URLName) + 1));\r
+ lstrcpyW(urlcopy, bind->URLName);\r
+ for (tmpwc = urlcopy; *tmpwc && *tmpwc != '#' && *tmpwc != '?'; ++tmpwc)\r
+ if (*tmpwc == '\\')\r
+ *tmpwc = '/';\r
+\r
#if 0\r
- if(!registered_wndclass) {\r
+ if(!registered_wndclass) {\r
WNDCLASSA urlmon_wndclass = {0, URLMON_WndProc,0, 0, URLMON_hInstance, 0, 0, 0, NULL, "URLMON_Callback_Window_Class"};\r
- RegisterClassA(&urlmon_wndclass);\r
- registered_wndclass = TRUE;\r
- }\r
+ RegisterClassA(&urlmon_wndclass);\r
+ registered_wndclass = TRUE;\r
+ }\r
\r
- This->hwndCallback = CreateWindowA("URLMON_Callback_Window_Class", NULL, 0, 0, 0, 0, 0, 0, 0,\r
- URLMON_hInstance, NULL);\r
+ This->hwndCallback = CreateWindowA("URLMON_Callback_Window_Class", NULL, 0, 0, 0, 0, 0, 0, 0,\r
+ URLMON_hInstance, NULL);\r
\r
#endif\r
+ bind->expected_size = 0;\r
+ bind->total_read = 0;\r
+\r
memset(&url, 0, sizeof(url));\r
url.dwStructSize = sizeof(url);\r
- url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = 1;\r
- InternetCrackUrlW(This->URLName, 0, 0, &url);\r
+ url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = url.dwUserNameLength = url.dwPasswordLength = 1;\r
+ InternetCrackUrlW(urlcopy, 0, 0, &url);\r
host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR));\r
memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));\r
host[url.dwHostNameLength] = '\0';\r
path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR));\r
memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));\r
path[url.dwUrlPathLength] = '\0';\r
+ if (url.dwUserNameLength)\r
+ {\r
+ user = HeapAlloc(GetProcessHeap(), 0, ((url.dwUserNameLength + 1) * sizeof(WCHAR)));\r
+ memcpy(user, url.lpszUserName, url.dwUserNameLength * sizeof(WCHAR));\r
+ user[url.dwUserNameLength] = 0;\r
+ }\r
+ else\r
+ {\r
+ user = 0;\r
+ }\r
+ if (url.dwPasswordLength)\r
+ {\r
+ pass = HeapAlloc(GetProcessHeap(), 0, ((url.dwPasswordLength + 1) * sizeof(WCHAR)));\r
+ memcpy(pass, url.lpszPassword, url.dwPasswordLength * sizeof(WCHAR));\r
+ pass[url.dwPasswordLength] = 0;\r
+ }\r
+ else\r
+ {\r
+ pass = 0;\r
+ }\r
\r
- This->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/);\r
-/* InternetSetStatusCallback(This->hinternet, URLMON_InternetCallback);*/\r
-\r
- This->hconnect = InternetConnectW(This->hinternet, host, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL,\r
- INTERNET_SERVICE_HTTP, 0, (DWORD)This);\r
- This->hrequest = HttpOpenRequestW(This->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)This);\r
-\r
- hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, 0x22, NULL);\r
- hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL);\r
- hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL);\r
- hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL);\r
- hres = E_OUTOFMEMORY; /* FIXME */\r
- if(HttpSendRequestW(This->hrequest, NULL, 0, NULL, 0)) {\r
- len = 0;\r
- HttpQueryInfoW(This->hrequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &len, &lensz, NULL);\r
-\r
- TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), len);\r
-\r
- last_read_pos.u.LowPart = last_read_pos.u.HighPart = 0;\r
- fmt.cfFormat = 0;\r
- fmt.ptd = NULL;\r
- fmt.dwAspect = 0;\r
- fmt.lindex = -1;\r
- fmt.tymed = TYMED_ISTREAM;\r
- stg.tymed = TYMED_ISTREAM;\r
- stg.u.pstm = pstr;\r
- stg.pUnkForRelease = NULL;\r
-\r
- while(1) {\r
- char buf[4096];\r
- DWORD bufread;\r
- DWORD written;\r
- if(InternetReadFile(This->hrequest, buf, sizeof(buf), &bufread)) {\r
- TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10));\r
- if(bufread == 0) break;\r
- IStream_Write(pstr, buf, bufread, &written);\r
- total_read += bufread;\r
- IStream_Seek(pstr, last_read_pos, STREAM_SEEK_SET, NULL);\r
- hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, (total_read == bufread) ?\r
- BINDSTATUS_BEGINDOWNLOADDATA :\r
- BINDSTATUS_DOWNLOADINGDATA, NULL);\r
- hres = IBindStatusCallback_OnDataAvailable(pbscb,\r
- (total_read == bufread) ? BSCF_FIRSTDATANOTIFICATION :\r
- BSCF_INTERMEDIATEDATANOTIFICATION,\r
- total_read, &fmt, &stg);\r
- last_read_pos.u.LowPart += bufread; /* FIXME */\r
- } else\r
+ switch ((DWORD) url.nScheme)\r
+ {\r
+ case INTERNET_SCHEME_FTP:\r
+ case INTERNET_SCHEME_GOPHER:\r
+ case INTERNET_SCHEME_HTTP:\r
+ case INTERNET_SCHEME_HTTPS:\r
+\r
+ bind->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/);\r
+/* InternetSetStatusCallback(bind->hinternet, URLMON_InternetCallback);*/\r
+ if (!bind->hinternet)\r
+ {\r
+ hres = HRESULT_FROM_WIN32(GetLastError());\r
break;\r
- }\r
- hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, BINDSTATUS_ENDDOWNLOADDATA, NULL);\r
- hres = IBindStatusCallback_OnDataAvailable(pbscb, BSCF_LASTDATANOTIFICATION, total_read, &fmt, &stg);\r
- TRACE("OnDataAvail rets %08lx\n", hres);\r
- hres = IBindStatusCallback_OnStopBinding(pbscb, S_OK, NULL);\r
- TRACE("OnStop rets %08lx\n", hres);\r
- hres = S_OK;\r
+ }\r
+\r
+ switch ((DWORD) url.nScheme)\r
+ {\r
+ case INTERNET_SCHEME_FTP:\r
+ if (!url.nPort)\r
+ url.nPort = INTERNET_DEFAULT_FTP_PORT;\r
+ dwService = INTERNET_SERVICE_FTP;\r
+ break;\r
+ \r
+ case INTERNET_SCHEME_GOPHER:\r
+ if (!url.nPort)\r
+ url.nPort = INTERNET_DEFAULT_GOPHER_PORT;\r
+ dwService = INTERNET_SERVICE_GOPHER;\r
+ break;\r
+\r
+ case INTERNET_SCHEME_HTTP:\r
+ if (!url.nPort)\r
+ url.nPort = INTERNET_DEFAULT_HTTP_PORT;\r
+ dwService = INTERNET_SERVICE_HTTP;\r
+ break;\r
+\r
+ case INTERNET_SCHEME_HTTPS:\r
+ if (!url.nPort)\r
+ url.nPort = INTERNET_DEFAULT_HTTPS_PORT;\r
+ dwService = INTERNET_SERVICE_HTTP;\r
+ break;\r
+ }\r
+\r
+ bind->hconnect = InternetConnectW(bind->hinternet, host, url.nPort, user, pass,\r
+ dwService, 0, (DWORD)bind);\r
+ if (!bind->hconnect)\r
+ {\r
+ hres = HRESULT_FROM_WIN32(GetLastError());\r
+ CloseHandle(bind->hinternet);\r
+ break;\r
+ }\r
+\r
+ hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, 0x22, NULL);\r
+ hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL);\r
+ hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL);\r
+ hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL);\r
+\r
+ bSuccess = FALSE;\r
+\r
+ switch (dwService)\r
+ {\r
+ case INTERNET_SERVICE_GOPHER:\r
+ bind->hrequest = GopherOpenFileW(bind->hconnect,\r
+ path,\r
+ 0,\r
+ INTERNET_FLAG_RELOAD,\r
+ 0);\r
+ if (bind->hrequest)\r
+ bSuccess = TRUE;\r
+ else\r
+ hres = HRESULT_FROM_WIN32(GetLastError());\r
+ break;\r
+\r
+ case INTERNET_SERVICE_FTP:\r
+ bind->hrequest = FtpOpenFileW(bind->hconnect,\r
+ path,\r
+ GENERIC_READ,\r
+ FTP_TRANSFER_TYPE_BINARY |\r
+ INTERNET_FLAG_TRANSFER_BINARY |\r
+ INTERNET_FLAG_RELOAD,\r
+ 0);\r
+ if (bind->hrequest)\r
+ bSuccess = TRUE;\r
+ else\r
+ hres = HRESULT_FROM_WIN32(GetLastError());\r
+ break;\r
+\r
+ case INTERNET_SERVICE_HTTP:\r
+ bind->hrequest = HttpOpenRequestW(bind->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)bind);\r
+ if (!bind->hrequest)\r
+ {\r
+ hres = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+ else if (!HttpSendRequestW(bind->hrequest, NULL, 0, NULL, 0))\r
+ {\r
+ hres = HRESULT_FROM_WIN32(GetLastError());\r
+ InternetCloseHandle(bind->hrequest);\r
+ }\r
+ else\r
+ {\r
+ HttpQueryInfoW(bind->hrequest,\r
+ HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,\r
+ &bind->expected_size,\r
+ &lensz,\r
+ NULL);\r
+ bSuccess = TRUE;\r
+ }\r
+ break;\r
+ }\r
+ if(bSuccess)\r
+ {\r
+ TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), bind->expected_size);\r
+\r
+ IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName);\r
+\r
+ while(1) {\r
+ char buf[4096];\r
+ DWORD bufread;\r
+ if(InternetReadFile(bind->hrequest, buf, sizeof(buf), &bufread)) {\r
+ TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10));\r
+ if(bufread == 0) break;\r
+ hres = Binding_MoreCacheData(bind, buf, bufread);\r
+ } else\r
+ break;\r
+ }\r
+ InternetCloseHandle(bind->hrequest);\r
+ hres = S_OK;\r
+ }\r
+ \r
+ InternetCloseHandle(bind->hconnect);\r
+ InternetCloseHandle(bind->hinternet);\r
+ break;\r
+\r
+ case INTERNET_SCHEME_FILE:\r
+ path = bind->URLName + 5; /* Skip the "file:" part */\r
+ if ((path[0] != '/' && path[0] != '\\') ||\r
+ (path[1] != '/' && path[1] != '\\'))\r
+ {\r
+ hres = E_FAIL;\r
+ }\r
+ else\r
+ {\r
+ HANDLE h;\r
+\r
+ path += 2;\r
+ if (path[0] == '/' || path[0] == '\\')\r
+ ++path;\r
+ h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );\r
+ if (h == (HANDLE) HFILE_ERROR)\r
+ {\r
+ hres = HRESULT_FROM_WIN32(GetLastError());\r
+ }\r
+ else\r
+ {\r
+ char buf[4096];\r
+ DWORD bufread;\r
+\r
+ IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName);\r
+\r
+ while (ReadFile(h, buf, sizeof(buf), &bufread, NULL) && bufread > 0)\r
+ hres = Binding_MoreCacheData(bind, buf, bufread);\r
+\r
+ CloseHandle(h);\r
+ hres = S_OK;\r
+ }\r
+ }\r
+ \r
+ break;\r
+\r
+ default:\r
+ FIXME("Unsupported URI scheme");\r
+ break;\r
}\r
- InternetCloseHandle(This->hrequest);\r
- InternetCloseHandle(This->hconnect);\r
- InternetCloseHandle(This->hinternet);\r
- IBindStatusCallback_Release(pbscb);\r
+ Binding_CloseCacheDownload(bind);\r
+ Binding_FinishedDownload(bind, hres);\r
+\r
+ if (user)\r
+ HeapFree(GetProcessHeap(), 0, user);\r
+ if (pass)\r
+ HeapFree(GetProcessHeap(), 0, pass);\r
+ HeapFree(GetProcessHeap(), 0, path);\r
+ HeapFree(GetProcessHeap(), 0, host);\r
+ HeapFree(GetProcessHeap(), 0, urlcopy);\r
}\r
}\r
}\r
- *ppvObject = (VOID*)pstr;\r
+\r
+ IBinding_Release((IBinding*)bind);\r
+\r
return hres;\r
}\r
\r
return S_OK;\r
}\r
\r
-static HRESULT WINAPI URLMonikerImpl_IBinding_QueryInterface(IBinding* iface,REFIID riid,void** ppvObject)\r
-{\r
- ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);\r
-\r
- TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);\r
-\r
- /* Perform a sanity check on the parameters.*/\r
- if ( (This==0) || (ppvObject==0) )\r
- return E_INVALIDARG;\r
-\r
- /* Initialize the return parameter */\r
- *ppvObject = 0;\r
-\r
- /* Compare the riid with the interface IDs implemented by this object.*/\r
- if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IBinding, riid))\r
- *ppvObject = iface;\r
-\r
- /* Check that we obtained an interface.*/\r
- if ((*ppvObject)==0)\r
- return E_NOINTERFACE;\r
-\r
- /* Query Interface always increases the reference count by one when it is successful */\r
- IBinding_AddRef(iface);\r
-\r
- return S_OK;\r
-\r
-}\r
-\r
-static ULONG WINAPI URLMonikerImpl_IBinding_AddRef(IBinding* iface)\r
-{\r
- ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);\r
- TRACE("(%p)\n",This);\r
-\r
- return URLMonikerImpl_AddRef((IMoniker*)This);\r
-}\r
-\r
-static ULONG WINAPI URLMonikerImpl_IBinding_Release(IBinding* iface)\r
-{\r
- ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);\r
- TRACE("(%p)\n",This);\r
-\r
- return URLMonikerImpl_Release((IMoniker*)This);\r
-}\r
-\r
-static HRESULT WINAPI URLMonikerImpl_IBinding_Abort(IBinding* iface)\r
-{\r
- ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);\r
- FIXME("(%p): stub\n", This);\r
-\r
- return E_NOTIMPL;\r
-}\r
-\r
-static HRESULT WINAPI URLMonikerImpl_IBinding_GetBindResult(IBinding* iface, CLSID* pclsidProtocol, DWORD* pdwResult, LPOLESTR* pszResult, DWORD* pdwReserved)\r
-{\r
- ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);\r
- FIXME("(%p)->(%p, %p, %p, %p): stub\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);\r
-\r
- return E_NOTIMPL;\r
-}\r
-\r
-static HRESULT WINAPI URLMonikerImpl_IBinding_GetPriority(IBinding* iface, LONG* pnPriority)\r
-{\r
- ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);\r
- FIXME("(%p)->(%p): stub\n", This, pnPriority);\r
-\r
- return E_NOTIMPL;\r
-}\r
-\r
-static HRESULT WINAPI URLMonikerImpl_IBinding_Resume(IBinding* iface)\r
-{\r
- ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);\r
- FIXME("(%p): stub\n", This);\r
-\r
- return E_NOTIMPL;\r
-}\r
-\r
-static HRESULT WINAPI URLMonikerImpl_IBinding_SetPriority(IBinding* iface, LONG nPriority)\r
-{\r
- ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);\r
- FIXME("(%p)->(%ld): stub\n", This, nPriority);\r
-\r
- return E_NOTIMPL;\r
-}\r
-\r
-static HRESULT WINAPI URLMonikerImpl_IBinding_Suspend(IBinding* iface)\r
-{\r
- ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface);\r
- FIXME("(%p): stub\n", This);\r
-\r
- return E_NOTIMPL;\r
-}\r
-\r
/********************************************************************************/\r
/* Virtual function table for the URLMonikerImpl class which include IPersist,*/\r
/* IPersistStream and IMoniker functions. */\r
URLMonikerImpl_IsSystemMoniker\r
};\r
\r
-static IBindingVtbl VTBinding_URLMonikerImpl =\r
-{\r
- URLMonikerImpl_IBinding_QueryInterface,\r
- URLMonikerImpl_IBinding_AddRef,\r
- URLMonikerImpl_IBinding_Release,\r
- URLMonikerImpl_IBinding_Abort,\r
- URLMonikerImpl_IBinding_Suspend,\r
- URLMonikerImpl_IBinding_Resume,\r
- URLMonikerImpl_IBinding_SetPriority,\r
- URLMonikerImpl_IBinding_GetPriority,\r
- URLMonikerImpl_IBinding_GetBindResult\r
-};\r
-\r
/******************************************************************************\r
* URLMoniker_Construct (local function)\r
*******************************************************************************/\r
memset(This, 0, sizeof(*This));\r
\r
/* Initialize the virtual function table. */\r
- This->lpvtbl1 = &VT_URLMonikerImpl;\r
- This->lpvtbl2 = &VTBinding_URLMonikerImpl;\r
- This->ref = 0;\r
+ This->lpvtbl = &VT_URLMonikerImpl;\r
+ This->ref = 0;\r
\r
if(lpszLeftURLName) {\r
hres = UrlCombineW(lpszLeftURLName, lpszURLName, NULL, &sizeStr, 0);\r
--- /dev/null
+/*
+ * Based on ../shell32/memorystream.c
+ *
+ * Copyright 1999 Juergen Schmied
+ * Copyright 2003 Mike McCormack 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
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#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);
+
+static const IStreamVtbl stvt;
+
+HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL,
+ DWORD dwSize,
+ LPWSTR pszFileName,
+ HANDLE *phfile,
+ IUMCacheStream **ppstr)
+{
+ IUMCacheStream* ucstr;
+ HANDLE handle;
+ LPWSTR ext;
+ LPCWSTR c;
+ LPCWSTR eloc = 0;
+ HRESULT hr;
+
+ for (c = pszURL; *c && *c != '#' && *c != '?'; ++c)
+ {
+ if (*c == '.')
+ eloc = c + 1;
+ else if (*c == '/' || *c == '\\')
+ eloc = 0;
+ }
+
+ if (!eloc)
+ eloc = c;
+
+ ext = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (c - eloc + 1));
+ memcpy(ext, eloc, sizeof(WCHAR) * (c - eloc));
+ ext[c - eloc] = 0;
+
+ if(!CreateUrlCacheEntryW(pszURL, dwSize, ext, pszFileName, 0))
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ else
+ hr = 0;
+
+ HeapFree(GetProcessHeap(), 0, ext);
+
+ if (hr)
+ return hr;
+
+ TRACE("Opening %s\n", debugstr_w(pszFileName) );
+
+ handle = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL );
+ if( handle == INVALID_HANDLE_VALUE )
+ return HRESULT_FROM_WIN32(GetLastError());
+
+ if (phfile)
+ {
+ /* Call CreateFileW again because we need a handle with its own file pointer, and DuplicateHandle will return
+ * a handle that shares its file pointer with the original.
+ */
+ *phfile = CreateFileW( pszFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
+
+ if (*phfile == (HANDLE) HFILE_ERROR)
+ {
+ DWORD dwError = GetLastError();
+
+ CloseHandle(handle);
+ return HRESULT_FROM_WIN32(dwError);
+ }
+ }
+
+ ucstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(IUMCacheStream));
+ if(ucstr )
+ {
+ ucstr->pszURL = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(WCHAR) * (lstrlenW(pszURL) + 1));
+ if (ucstr->pszURL)
+ {
+ ucstr->pszFileName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(WCHAR) * (lstrlenW(pszFileName) + 1));
+ if (ucstr->pszFileName)
+ {
+ ucstr->lpVtbl=&stvt;
+ ucstr->ref = 1;
+ ucstr->handle = handle;
+ ucstr->closed = 0;
+ lstrcpyW(ucstr->pszURL, pszURL);
+ lstrcpyW(ucstr->pszFileName, pszFileName);
+
+ *ppstr = ucstr;
+
+ return S_OK;
+ }
+ HeapFree(GetProcessHeap(), 0, ucstr->pszURL);
+ }
+ HeapFree(GetProcessHeap(), 0, ucstr);
+ }
+ CloseHandle(handle);
+ if (phfile)
+ CloseHandle(*phfile);
+ return E_OUTOFMEMORY;
+}
+
+void UMCloseCacheFileStream(IUMCacheStream *This)
+{
+ if (!This->closed)
+ {
+ FILETIME ftZero;
+
+ ftZero.dwLowDateTime = ftZero.dwHighDateTime = 0;
+
+ This->closed = 1;
+ CommitUrlCacheEntryW(This->pszURL,
+ This->pszFileName,
+ ftZero,
+ ftZero,
+ NORMAL_CACHE_ENTRY,
+ 0,
+ 0,
+ 0,
+ 0);
+ }
+}
+
+/**************************************************************************
+* IStream_fnQueryInterface
+*/
+static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
+
+ *ppvObj = NULL;
+
+ if(IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_IStream))
+ {
+ *ppvObj = This;
+ }
+
+ if(*ppvObj)
+ {
+ IStream_AddRef((IStream*)*ppvObj);
+ TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
+ return S_OK;
+ }
+ TRACE("-- Interface: E_NOINTERFACE\n");
+ return E_NOINTERFACE;
+}
+
+/**************************************************************************
+* IStream_fnAddRef
+*/
+static ULONG WINAPI IStream_fnAddRef(IStream *iface)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+ ULONG refCount = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p)->(count=%lu)\n", This, refCount - 1);
+
+ return refCount;
+}
+
+/**************************************************************************
+* IStream_fnRelease
+*/
+static ULONG WINAPI IStream_fnRelease(IStream *iface)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+ ULONG refCount = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p)->(count=%lu)\n", This, refCount + 1);
+
+ if (!refCount)
+ {
+ TRACE(" destroying UMCacheStream (%p)\n",This);
+ UMCloseCacheFileStream(This);
+ CloseHandle(This->handle);
+ HeapFree(GetProcessHeap(), 0, This->pszFileName);
+ HeapFree(GetProcessHeap(), 0, This->pszURL);
+ HeapFree(GetProcessHeap(),0,This);
+ }
+ return refCount;
+}
+
+static HRESULT WINAPI IStream_fnRead (IStream * iface,
+ void* pv,
+ ULONG cb,
+ ULONG* pcbRead)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)->(%p,0x%08lx,%p)\n",This, pv, cb, pcbRead);
+
+ if ( !pv )
+ return STG_E_INVALIDPOINTER;
+
+ if ( ! ReadFile( This->handle, pv, cb, pcbRead, NULL ) )
+ return S_FALSE;
+
+ if (!*pcbRead)
+ return This->closed ? S_FALSE : E_PENDING;
+ return S_OK;
+}
+
+static HRESULT WINAPI IStream_fnWrite (IStream * iface,
+ const void* pv,
+ ULONG cb,
+ ULONG* pcbWritten)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IStream_fnSeek ( IStream * iface,
+ LARGE_INTEGER dlibMove,
+ DWORD dwOrigin,
+ ULARGE_INTEGER* plibNewPosition)
+{
+ DWORD pos, newposlo, newposhi;
+
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)\n",This);
+
+ pos = dlibMove.QuadPart; /* FIXME: truncates */
+ newposhi = 0;
+ newposlo = SetFilePointer( This->handle, pos, &newposhi, dwOrigin );
+ if( newposlo == INVALID_SET_FILE_POINTER )
+ return E_FAIL;
+
+ if (plibNewPosition)
+ plibNewPosition->QuadPart = newposlo | ( (LONGLONG)newposhi<<32);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IStream_fnSetSize (IStream * iface,
+ ULARGE_INTEGER libNewSize)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)\n",This);
+
+ if( ! SetFilePointer( This->handle, libNewSize.QuadPart, NULL, FILE_BEGIN ) )
+ return E_FAIL;
+
+ if( ! SetEndOfFile( This->handle ) )
+ return E_FAIL;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IStream_fnCopyTo (IStream * iface,
+ IStream* pstm,
+ ULARGE_INTEGER cb,
+ ULARGE_INTEGER* pcbRead,
+ ULARGE_INTEGER* pcbWritten)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IStream_fnCommit (IStream * iface,
+ DWORD grfCommitFlags)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IStream_fnRevert (IStream * iface)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)\n",This);
+
+ return E_NOTIMPL;
+}
+static HRESULT WINAPI IStream_fnLockRegion (IStream * iface,
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)\n",This);
+
+ return E_NOTIMPL;
+}
+static HRESULT WINAPI IStream_fnUnlockRegion (IStream * iface,
+ ULARGE_INTEGER libOffset,
+ ULARGE_INTEGER cb,
+ DWORD dwLockType)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)\n",This);
+
+ return E_NOTIMPL;
+}
+static HRESULT WINAPI IStream_fnStat (IStream * iface,
+ STATSTG* pstatstg,
+ DWORD grfStatFlag)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)\n",This);
+
+ return E_NOTIMPL;
+}
+static HRESULT WINAPI IStream_fnClone (IStream * iface,
+ IStream** ppstm)
+{
+ IUMCacheStream *This = (IUMCacheStream *)iface;
+
+ TRACE("(%p)\n",This);
+
+ return E_NOTIMPL;
+}
+
+static const IStreamVtbl stvt =
+{
+ IStream_fnQueryInterface,
+ IStream_fnAddRef,
+ IStream_fnRelease,
+ IStream_fnRead,
+ IStream_fnWrite,
+ IStream_fnSeek,
+ IStream_fnSetSize,
+ IStream_fnCopyTo,
+ IStream_fnCommit,
+ IStream_fnRevert,
+ IStream_fnLockRegion,
+ IStream_fnUnlockRegion,
+ IStream_fnStat,
+ IStream_fnClone
+
+};