diff --git a/dlls/urlmon/tests/Makefile.in b/dlls/urlmon/tests/Makefile.in index 03ab73a5480..7e3048b2f0c 100644 --- a/dlls/urlmon/tests/Makefile.in +++ b/dlls/urlmon/tests/Makefile.in @@ -3,7 +3,8 @@ TOPOBJDIR = ../../.. SRCDIR = @srcdir@ VPATH = @srcdir@ TESTDLL = urlmon.dll -IMPORTS = urlmon +IMPORTS = urlmon user32 +EXTRALIBS = -luuid CTESTS = \ generated.c \ diff --git a/dlls/urlmon/tests/url.c b/dlls/urlmon/tests/url.c index b0e2960c4ec..8dbf323072b 100644 --- a/dlls/urlmon/tests/url.c +++ b/dlls/urlmon/tests/url.c @@ -29,9 +29,19 @@ #include "wine/test.h" +#ifdef NONAMELESSUNION +# define U(x) (x).u +#else +# define U(x) (x) +#endif + static const WCHAR TEST_URL_1[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','\0'}; static const WCHAR TEST_PART_URL_1[] = {'/','t','e','s','t','/','\0'}; +static const WCHAR WINE_ABOUT_URL[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.', + 'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0}; +static BOOL stopped_binding = FALSE; + static void test_CreateURLMoniker(LPCWSTR url1, LPCWSTR url2) { HRESULT hr; @@ -56,6 +66,8 @@ static void test_create() typedef struct { IBindStatusCallbackVtbl *lpVtbl; ULONG ref; + IBinding *pbind; + IStream *pstr; } statusclb; static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppvObject) @@ -78,12 +90,19 @@ static ULONG WINAPI statusclb_Release(IBindStatusCallback *iface) return ref; } -static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface,DWORD dwReserved, IBinding * pib) +static HRESULT WINAPI statusclb_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved, IBinding *pib) { - return E_NOTIMPL; + statusclb *This = (statusclb*)iface; + + This->pbind = pib; + ok(pib != NULL, "pib should not be NULL\n"); + if(pib) + IBinding_AddRef(pib); + + return S_OK; } -static HRESULT WINAPI statusclb_GetPriority(IBindStatusCallback *iface, LONG * pnPriority) +static HRESULT WINAPI statusclb_GetPriority(IBindStatusCallback *iface, LONG *pnPriority) { return E_NOTIMPL; } @@ -96,26 +115,58 @@ static HRESULT WINAPI statusclb_OnLowResource(IBindStatusCallback *iface, DWORD static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) { - return E_NOTIMPL; + return S_OK; } static HRESULT WINAPI statusclb_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError) { - return E_NOTIMPL; + statusclb *This = (statusclb*)iface; + + ok(SUCCEEDED(hresult), "Download failed: %08lx\n", hresult); + ok(szError == NULL, "szError should be NULL\n"); + stopped_binding = TRUE; + IBinding_Release(This->pbind); + ok(This->pstr != NULL, "pstr should not be NULL here\n"); + if(This->pstr) + IStream_Release(This->pstr); + + return S_OK; } -static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO * pbindinfo) +static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo) { - return E_NOTIMPL; + DWORD cbSize; + + *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; + cbSize = pbindinfo->cbSize; + memset(pbindinfo, 0, cbSize); + pbindinfo->cbSize = cbSize; + + return S_OK; } static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF, DWORD dwSize, - FORMATETC* pformatetc, STGMEDIUM* pstgmed) + FORMATETC* pformatetc, STGMEDIUM* pstgmed) { - return E_NOTIMPL; + statusclb *This = (statusclb*)iface; + HRESULT hres; + DWORD readed; + BYTE buf[512]; + if(!This->pstr) { + ok(grfBSCF & BSCF_FIRSTDATANOTIFICATION, "pstr should be set when BSCF_FIRSTDATANOTIFICATION\n"); + This->pstr = U(*pstgmed).pstm; + IStream_AddRef(This->pstr); + ok(This->pstr != NULL, "pstr should not be NULL here\n"); + } + + do hres = IStream_Read(This->pstr, buf, 512, &readed); + while(hres == S_OK); + ok(hres == S_FALSE || hres == E_PENDING, "IStream_Read returned %08lx\n", hres); + + return S_OK; } -static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown* punk) +static HRESULT WINAPI statusclb_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk) { return E_NOTIMPL; } @@ -139,6 +190,8 @@ static IBindStatusCallback* statusclb_create() statusclb *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(statusclb)); ret->lpVtbl = &statusclbVtbl; ret->ref = 1; + ret->pbind = NULL; + ret->pstr = NULL; return (IBindStatusCallback*)ret; } @@ -180,8 +233,67 @@ static void test_CreateAsyncBindCtx() ok(ref == 0, "bsc should be destroyed here\n"); } +static void test_BindToStorage() +{ + IMoniker *mon; + HRESULT hres; + LPOLESTR display_name; + IBindCtx *bctx; + MSG msg; + IBindStatusCallback *previousclb, *sclb = statusclb_create(); + IUnknown *unk = (IUnknown*)0x00ff00ff; + + hres = CreateAsyncBindCtx(0, sclb, NULL, &bctx); + ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08lx\n\n", hres); + if(FAILED(hres)) { + IBindStatusCallback_Release(sclb); + return; + } + + hres = RegisterBindStatusCallback(bctx, sclb, &previousclb, 0); + ok(SUCCEEDED(hres), "RegisterBindStatusCallback failed: %08lx\n", hres); + ok(previousclb == sclb, "previousclb(%p) != sclb(%p)\n", previousclb, sclb); + if(previousclb) + IBindStatusCallback_Release(previousclb); + + hres = CreateURLMoniker(NULL, WINE_ABOUT_URL, &mon); + ok(SUCCEEDED(hres), "failed to create moniker: %08lx\n", hres); + if(FAILED(hres)) { + IBindStatusCallback_Release(sclb); + IBindCtx_Release(bctx); + return; + } + + hres = IMoniker_GetDisplayName(mon, bctx, NULL, &display_name); + ok(SUCCEEDED(hres), "GetDisplayName failed %08lx\n", hres); + ok(!lstrcmpW(display_name, WINE_ABOUT_URL), "GetDisplayName got wrong name\n"); + + hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk); + ok(SUCCEEDED(hres), "IMoniker_BindToStorage failed: %08lx\n", hres); + todo_wine { + ok(unk == NULL, "istr should be NULL\n"); + } + if(FAILED(hres)) { + IBindStatusCallback_Release(sclb); + IMoniker_Release(mon); + return; + } + if(unk) + IUnknown_Release(unk); + + while(!stopped_binding && GetMessage(&msg,NULL,0,0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n"); + ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n"); + ok(IBindStatusCallback_Release(sclb) == 0, "scbl should be destroyed here\n"); +} + START_TEST(url) { test_create(); test_CreateAsyncBindCtx(); + test_BindToStorage(); } diff --git a/dlls/urlmon/umon.c b/dlls/urlmon/umon.c index 2b473693ad4..266c94f848e 100644 --- a/dlls/urlmon/umon.c +++ b/dlls/urlmon/umon.c @@ -324,6 +324,7 @@ static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface, IBindStatusCallback *pbscb; BINDINFO bi; DWORD bindf; + IStream *pstr; FIXME("(%p)->(%p,%p,%s,%p): stub\n",This,pbc,pmkToLeft,debugstr_guid(riid),ppvObject); if(pmkToLeft) { @@ -339,32 +340,31 @@ static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface, We also need to implement IStream ourselves so that IStream_Read can return E_PENDING */ - hres = CreateStreamOnHGlobal(0, TRUE, (IStream**)ppvObject); - + hres = CreateStreamOnHGlobal(0, TRUE, &pstr); if(SUCCEEDED(hres)) { - TRACE("Created dummy stream...\n"); + TRACE("Created dummy stream...\n"); - hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&pbscb); - if(SUCCEEDED(hres)) { - TRACE("Got IBindStatusCallback...\n"); + hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&pbscb); + if(SUCCEEDED(hres)) { + TRACE("Got IBindStatusCallback...\n"); - memset(&bi, 0, sizeof(bi)); - bi.cbSize = sizeof(bi); - bindf = 0; - hres = IBindStatusCallback_GetBindInfo(pbscb, &bindf, &bi); - if(SUCCEEDED(hres)) { - URL_COMPONENTSW url; - WCHAR *host, *path; - DWORD len, lensz = sizeof(len), total_read = 0; - LARGE_INTEGER last_read_pos; - FORMATETC fmt; - STGMEDIUM stg; + memset(&bi, 0, sizeof(bi)); + bi.cbSize = sizeof(bi); + bindf = 0; + hres = IBindStatusCallback_GetBindInfo(pbscb, &bindf, &bi); + if(SUCCEEDED(hres)) { + URL_COMPONENTSW url; + WCHAR *host, *path; + DWORD len, lensz = sizeof(len), total_read = 0; + LARGE_INTEGER last_read_pos; + FORMATETC fmt; + STGMEDIUM stg; - TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n", - bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid)); - hres = IBindStatusCallback_OnStartBinding(pbscb, 0, (IBinding*)&This->lpvtbl2); - TRACE("OnStartBinding rets %08lx\n", hres); + TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n", + bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid)); + hres = IBindStatusCallback_OnStartBinding(pbscb, 0, (IBinding*)&This->lpvtbl2); + TRACE("OnStartBinding rets %08lx\n", hres); #if 0 if(!registered_wndclass) { @@ -377,80 +377,81 @@ static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface, URLMON_hInstance, NULL); #endif - memset(&url, 0, sizeof(url)); - url.dwStructSize = sizeof(url); - url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = 1; - InternetCrackUrlW(This->URLName, 0, 0, &url); - host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR)); - memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR)); - host[url.dwHostNameLength] = '\0'; - path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR)); - memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR)); - path[url.dwUrlPathLength] = '\0'; + memset(&url, 0, sizeof(url)); + url.dwStructSize = sizeof(url); + url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = 1; + InternetCrackUrlW(This->URLName, 0, 0, &url); + host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR)); + memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR)); + host[url.dwHostNameLength] = '\0'; + path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR)); + memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR)); + path[url.dwUrlPathLength] = '\0'; - This->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/); -/* InternetSetStatusCallback(This->hinternet, URLMON_InternetCallback);*/ + This->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/); +/* InternetSetStatusCallback(This->hinternet, URLMON_InternetCallback);*/ - This->hconnect = InternetConnectW(This->hinternet, host, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, - INTERNET_SERVICE_HTTP, 0, (DWORD)This); - This->hrequest = HttpOpenRequestW(This->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)This); + This->hconnect = InternetConnectW(This->hinternet, host, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, + INTERNET_SERVICE_HTTP, 0, (DWORD)This); + This->hrequest = HttpOpenRequestW(This->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)This); - hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, 0x22, NULL); - hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL); - hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL); - hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL); - hres = E_OUTOFMEMORY; /* FIXME */ - if(HttpSendRequestW(This->hrequest, NULL, 0, NULL, 0)) { + hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, 0x22, NULL); + hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL); + hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL); + hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL); + hres = E_OUTOFMEMORY; /* FIXME */ + if(HttpSendRequestW(This->hrequest, NULL, 0, NULL, 0)) { + len = 0; + HttpQueryInfoW(This->hrequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &len, &lensz, NULL); - len = 0; - HttpQueryInfoW(This->hrequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &len, &lensz, NULL); + TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), len); - TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), len); + last_read_pos.u.LowPart = last_read_pos.u.HighPart = 0; + fmt.cfFormat = 0; + fmt.ptd = NULL; + fmt.dwAspect = 0; + fmt.lindex = -1; + fmt.tymed = TYMED_ISTREAM; + stg.tymed = TYMED_ISTREAM; + stg.u.pstm = pstr; + stg.pUnkForRelease = NULL; - last_read_pos.u.LowPart = last_read_pos.u.HighPart = 0; - fmt.cfFormat = 0; - fmt.ptd = NULL; - fmt.dwAspect = 0; - fmt.lindex = -1; - fmt.tymed = TYMED_ISTREAM; - stg.tymed = TYMED_ISTREAM; - stg.u.pstm = *(IStream**)ppvObject; - stg.pUnkForRelease = NULL; - - while(1) { - char buf[4096]; - DWORD bufread; - DWORD written; - if(InternetReadFile(This->hrequest, buf, sizeof(buf), &bufread)) { - TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10)); - if(bufread == 0) break; - IStream_Write(*(IStream**)ppvObject, buf, bufread, &written); - total_read += bufread; - IStream_Seek(*(IStream**)ppvObject, last_read_pos, STREAM_SEEK_SET, NULL); - hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, (total_read == bufread) ? - BINDSTATUS_BEGINDOWNLOADDATA : - BINDSTATUS_DOWNLOADINGDATA, NULL); - hres = IBindStatusCallback_OnDataAvailable(pbscb, - (total_read == bufread) ? BSCF_FIRSTDATANOTIFICATION : - BSCF_INTERMEDIATEDATANOTIFICATION, - total_read, &fmt, &stg); - last_read_pos.u.LowPart += bufread; /* FIXME */ - } else - break; + while(1) { + char buf[4096]; + DWORD bufread; + DWORD written; + if(InternetReadFile(This->hrequest, buf, sizeof(buf), &bufread)) { + TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10)); + if(bufread == 0) break; + IStream_Write(pstr, buf, bufread, &written); + total_read += bufread; + IStream_Seek(pstr, last_read_pos, STREAM_SEEK_SET, NULL); + hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, (total_read == bufread) ? + BINDSTATUS_BEGINDOWNLOADDATA : + BINDSTATUS_DOWNLOADINGDATA, NULL); + hres = IBindStatusCallback_OnDataAvailable(pbscb, + (total_read == bufread) ? BSCF_FIRSTDATANOTIFICATION : + BSCF_INTERMEDIATEDATANOTIFICATION, + total_read, &fmt, &stg); + last_read_pos.u.LowPart += bufread; /* FIXME */ + } else + break; } - hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, BINDSTATUS_ENDDOWNLOADDATA, NULL); - hres = IBindStatusCallback_OnDataAvailable(pbscb, BSCF_LASTDATANOTIFICATION, total_read, &fmt, &stg); - TRACE("OnDataAvail rets %08lx\n", hres); - hres = IBindStatusCallback_OnStopBinding(pbscb, S_OK, NULL); - TRACE("OnStop rets %08lx\n", hres); - hres = S_OK; - } - InternetCloseHandle(This->hrequest); - InternetCloseHandle(This->hconnect); - InternetCloseHandle(This->hinternet); - } - } + hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, BINDSTATUS_ENDDOWNLOADDATA, NULL); + hres = IBindStatusCallback_OnDataAvailable(pbscb, BSCF_LASTDATANOTIFICATION, total_read, &fmt, &stg); + TRACE("OnDataAvail rets %08lx\n", hres); + hres = IBindStatusCallback_OnStopBinding(pbscb, S_OK, NULL); + TRACE("OnStop rets %08lx\n", hres); + hres = S_OK; + } + InternetCloseHandle(This->hrequest); + InternetCloseHandle(This->hconnect); + InternetCloseHandle(This->hinternet); + IBindStatusCallback_Release(pbscb); + } + } } + *ppvObject = (VOID*)pstr; return hres; } @@ -752,7 +753,7 @@ static HRESULT WINAPI URLMonikerImpl_IBinding_Abort(IBinding* iface) static HRESULT WINAPI URLMonikerImpl_IBinding_GetBindResult(IBinding* iface, CLSID* pclsidProtocol, DWORD* pdwResult, LPOLESTR* pszResult, DWORD* pdwReserved) { ICOM_THIS_MULTI(URLMonikerImpl, lpvtbl2, iface); - FIXME("(%p)->(%s, %p, %p, %p): stub\n", This, debugstr_guid(pclsidProtocol), pdwResult, pszResult, pdwReserved); + FIXME("(%p)->(%p, %p, %p, %p): stub\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved); return E_NOTIMPL; } diff --git a/include/urlmon.idl b/include/urlmon.idl index 73168cb1b51..a77683d5f04 100644 --- a/include/urlmon.idl +++ b/include/urlmon.idl @@ -73,6 +73,13 @@ interface IBindStatusCallback : IUnknown { typedef [unique] IBindStatusCallback *LPBINDSTATUSCALLBACK; + typedef enum + { + BINDVERB_GET = 0x00000000, + BINDVERB_POST = 0x00000001, + BINDVERB_PUT = 0x00000002, + BINDVERB_CUSTOM = 0x00000003 + } BINDVERB; typedef enum { @@ -265,6 +272,24 @@ interface IBindStatusCallback : IUnknown [in, iid_is(riid)] IUnknown* punk); } +/***************************************************************************** + * IAuthenticate interface + */ +[ + local, + object, + uuid(79EAC9D0-BAf9-11CE-8C82-00AA004BA90B), + pointer_default(unique) +] +interface IAuthenticate : IUnknown +{ + typedef [unique] IAuthenticate *LPAUTHENTICATION; + + HRESULT Authenticate( + [out] HWND* phwnd, + [out] LPWSTR *pszUsername, + [out] LPWSTR *pszPassword); +} /***************************************************************************** * IBindHost interface @@ -791,6 +816,7 @@ interface IInternetZoneManager : IUnknown cpp_quote("DEFINE_GUID(CLSID_InternetSecurityManager, 0x7b8a2d94, 0x0ac9, 0x11d1, 0x89, 0x6c, 0x00, 0xc0, 0x4f, 0xB6, 0xbf, 0xc4);") cpp_quote("DEFINE_GUID(CLSID_InternetZoneManager, 0x7B8A2D95, 0x0AC9, 0x11D1, 0x89, 0x6C, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4);") cpp_quote("DEFINE_GUID(IID_IAsyncMoniker, 0x79EAC9D3, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B);") +cpp_quote("DEFINE_GUID(IID_IAsyncBindCtx, 0x79EAC9D4, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B);") cpp_quote("DEFINE_GUID(CLSID_StdURLMoniker, 0x79EAC9E0, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B);") cpp_quote("#define MK_S_ASYNCHRONOUS 0x000401E8")