diff --git a/dlls/urlmon/Makefile.in b/dlls/urlmon/Makefile.in index 988cdeb5d1d..831f5ebfaca 100644 --- a/dlls/urlmon/Makefile.in +++ b/dlls/urlmon/Makefile.in @@ -8,6 +8,7 @@ IMPORTS = cabinet ole32 shlwapi wininet user32 advapi32 kernel32 ntdll EXTRALIBS = -luuid C_SRCS = \ + file.c \ format.c \ regsvr.c \ sec_mgr.c \ diff --git a/dlls/urlmon/file.c b/dlls/urlmon/file.c new file mode 100644 index 00000000000..334bd95b08f --- /dev/null +++ b/dlls/urlmon/file.c @@ -0,0 +1,265 @@ +/* + * Copyright 2005 Jacek Caban + * + * 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 + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "urlmon.h" +#include "urlmon_main.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(urlmon); + +typedef struct { + const IInternetProtocolVtbl *lpInternetProtocolVtbl; + + HANDLE file; + + LONG ref; +} FileProtocol; + +#define PROTOCOL_THIS(iface) DEFINE_THIS(FileProtocol, InternetProtocol, iface) + +#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) + +static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + + *ppv = NULL; + if(IsEqualGUID(&IID_IUnknown, riid)) { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = PROTOCOL(This); + }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) { + TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv); + *ppv = PROTOCOL(This); + }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) { + TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv); + *ppv = PROTOCOL(This); + } + + if(*ppv) { + IInternetProtocol_AddRef(iface); + return S_OK; + } + + WARN("not supported interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI FileProtocol_AddRef(IInternetProtocol *iface) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) ref=%ld\n", This, ref); + return ref; +} + +static ULONG WINAPI FileProtocol_Release(IInternetProtocol *iface) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + if(This->file) + CloseHandle(This->file); + HeapFree(GetProcessHeap(), 0, This); + + URLMON_UnlockModule(); + } + + return ref; +} + +static HRESULT WINAPI FileProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, + IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, + DWORD grfPI, DWORD dwReserved) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + BINDINFO bindinfo; + DWORD grfBINDF = 0; + LARGE_INTEGER size; + + static const WCHAR wszFile[] = {'f','i','l','e',':'}; + + TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink, + pOIBindInfo, grfPI, dwReserved); + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(BINDINFO); + IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo); + + if(lstrlenW(szUrl) < sizeof(wszFile)/sizeof(WCHAR) + || memcmp(szUrl, wszFile, sizeof(wszFile))) + return MK_E_SYNTAX; + + /* FIXME: + * Implement MIME type checking + */ + + if(!This->file) { + This->file = CreateFileW(szUrl+sizeof(wszFile)/sizeof(WCHAR), GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if(This->file == INVALID_HANDLE_VALUE) { + This->file = NULL; + IInternetProtocolSink_ReportResult(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, + GetLastError(), NULL); + return INET_E_RESOURCE_NOT_FOUND; + } + + IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_CACHEFILENAMEAVAILABLE, + szUrl+sizeof(wszFile)/sizeof(WCHAR)); + IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL); + } + + if(GetFileSizeEx(This->file, &size)) + IInternetProtocolSink_ReportData(pOIProtSink, + BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION, + size.u.LowPart, size.u.LowPart); + + return S_OK; +} + +static HRESULT WINAPI FileProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%p)\n", This, pProtocolData); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, + DWORD dwOptions) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%08lx)\n", This, dwOptions); + + return S_OK; +} + +static HRESULT WINAPI FileProtocol_Suspend(IInternetProtocol *iface) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileProtocol_Resume(IInternetProtocol *iface) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileProtocol_Read(IInternetProtocol *iface, void *pv, + ULONG cb, ULONG *pcbRead) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + DWORD read = 0; + + TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead); + + if(!This->file) + return INET_E_DATA_NOT_AVAILABLE; + + ReadFile(This->file, pv, cb, &read, NULL); + + if(pcbRead) + *pcbRead = read; + + return cb == read ? S_OK : S_FALSE; +} + +static HRESULT WINAPI FileProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, + DWORD dwOrgin, ULARGE_INTEGER *plibNewPosition) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrgin, plibNewPosition); + return E_NOTIMPL; +} + +static HRESULT WINAPI FileProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%08lx)\n", This, dwOptions); + + return S_OK; +} + +static HRESULT WINAPI FileProtocol_UnlockRequest(IInternetProtocol *iface) +{ + FileProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)\n", This); + + return S_OK; +} + +#undef PROTOCOL_THIS + +static const IInternetProtocolVtbl FileProtocolVtbl = { + FileProtocol_QueryInterface, + FileProtocol_AddRef, + FileProtocol_Release, + FileProtocol_Start, + FileProtocol_Continue, + FileProtocol_Abort, + FileProtocol_Terminate, + FileProtocol_Suspend, + FileProtocol_Resume, + FileProtocol_Read, + FileProtocol_Seek, + FileProtocol_LockRequest, + FileProtocol_UnlockRequest +}; + +HRESULT FileProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) +{ + FileProtocol *ret; + + TRACE("(%p %p)\n", pUnkOuter, ppobj); + + URLMON_LockModule(); + + ret = HeapAlloc(GetProcessHeap(), 0, sizeof(FileProtocol)); + + ret->lpInternetProtocolVtbl = &FileProtocolVtbl; + ret->file = NULL; + ret->ref = 1; + + *ppobj = PROTOCOL(ret); + + return S_OK; +} diff --git a/dlls/urlmon/tests/.cvsignore b/dlls/urlmon/tests/.cvsignore index 2fd26cd097f..f8578b0684c 100644 --- a/dlls/urlmon/tests/.cvsignore +++ b/dlls/urlmon/tests/.cvsignore @@ -1,5 +1,6 @@ Makefile generated.ok misc.ok +protocol.ok testlist.c url.ok diff --git a/dlls/urlmon/tests/Makefile.in b/dlls/urlmon/tests/Makefile.in index c9045a2338a..8994fad8ea6 100644 --- a/dlls/urlmon/tests/Makefile.in +++ b/dlls/urlmon/tests/Makefile.in @@ -9,6 +9,7 @@ EXTRALIBS = -luuid CTESTS = \ generated.c \ misc.c \ + protocol.c \ url.c @MAKE_TEST_RULES@ diff --git a/dlls/urlmon/tests/protocol.c b/dlls/urlmon/tests/protocol.c new file mode 100644 index 00000000000..d57770def3e --- /dev/null +++ b/dlls/urlmon/tests/protocol.c @@ -0,0 +1,409 @@ +/* + * Copyright 2005 Jacek Caban + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COBJMACROS + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "ole2.h" +#include "urlmon.h" + +#include "initguid.h" + +DEFINE_GUID(CLSID_FileProtocol, 0x79EAC9E7, 0xBAF9, 0x11CE, 0x8C,0x82, 0x00,0xAA,0x00,0x4B,0xA9,0x0B); + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT(func) \ + ok(expect_ ##func, "unexpected call\n"); \ + expect_ ## func = FALSE; \ + called_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + ok(expect_ ##func, "unexpected call\n"); \ + called_ ## func = TRUE + +#define CHECK_CALLED(func) \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE + +DEFINE_EXPECT(GetBindInfo); +DEFINE_EXPECT(ReportProgress_MIMETYPEAVAILABLE); +DEFINE_EXPECT(ReportProgress_DIRECTBIND); +DEFINE_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE); +DEFINE_EXPECT(ReportData); +DEFINE_EXPECT(ReportResult); + +static HRESULT expect_hrResult; +static LPCWSTR file_name; + +static HRESULT WINAPI ProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocolSink, riid)) { + *ppv = iface; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI ProtocolSink_AddRef(IInternetProtocolSink *iface) +{ + return 2; +} + +static ULONG WINAPI ProtocolSink_Release(IInternetProtocolSink *iface) +{ + return 1; +} + +static HRESULT WINAPI ProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode, + LPCWSTR szStatusText) +{ + static const WCHAR text_html[] = {'t','e','x','t','/','h','t','m','l',0}; + + switch(ulStatusCode) { + case BINDSTATUS_MIMETYPEAVAILABLE: + CHECK_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + if(szStatusText) + ok(!lstrcmpW(szStatusText, text_html), "szStatusText != text/html\n"); + case BINDSTATUS_DIRECTBIND: + CHECK_EXPECT2(ReportProgress_DIRECTBIND); + if(szStatusText) + ok(!lstrcmpW(szStatusText, text_html), "szStatusText != text/html\n"); + break; + case BINDSTATUS_CACHEFILENAMEAVAILABLE: + CHECK_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE); + if(szStatusText) + ok(!lstrcmpW(szStatusText, file_name), "szStatusText != file_name\n"); + break; + }; + + return S_OK; +} + +static HRESULT WINAPI ProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF, + ULONG ulProgress, ULONG ulProgressMax) +{ + CHECK_EXPECT(ReportData); + + ok(ulProgress == ulProgressMax, "ulProgress != ulProgressMax\n"); + ok(ulProgressMax == 13, "ulProgressMax=%ld, expected 13\n", ulProgressMax); + ok(grfBSCF == (BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION), + "grcf = %08lx\n", grfBSCF); + + return S_OK; +} + +static HRESULT WINAPI ProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult, + DWORD dwError, LPCWSTR szResult) +{ + CHECK_EXPECT(ReportResult); + + ok(hrResult == expect_hrResult, "hrResult = %08lx, expected: %08lx\n", + hrResult, expect_hrResult); + if(SUCCEEDED(hrResult)) + ok(dwError == ERROR_SUCCESS, "dwError = %ld, expected ERROR_SUCCESS\n", dwError); + else + ok(dwError != ERROR_SUCCESS, "dwError == ERROR_SUCCESS\n"); + ok(!szResult, "szResult != NULL\n"); + + return S_OK; +} + +static IInternetProtocolSinkVtbl protocol_sink_vtbl = { + ProtocolSink_QueryInterface, + ProtocolSink_AddRef, + ProtocolSink_Release, + ProtocolSink_Switch, + ProtocolSink_ReportProgress, + ProtocolSink_ReportData, + ProtocolSink_ReportResult +}; + +static IInternetProtocolSink protocol_sink = { &protocol_sink_vtbl }; + +static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetBindInfo, riid)) { + *ppv = iface; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface) +{ + return 2; +} + +static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface) +{ + return 1; +} + +static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *grfBINDF, BINDINFO *pbindinfo) +{ + CHECK_EXPECT(GetBindInfo); + + ok(grfBINDF != NULL, "grfBINDF == NULL\n"); + if(grfBINDF) + ok(!*grfBINDF, "*grfBINDF != 0\n"); + ok(pbindinfo != NULL, "pbindinfo == NULL\n"); + ok(pbindinfo->cbSize == sizeof(BINDINFO), "wrong size of pbindinfo: %ld\n", pbindinfo->cbSize); + + return S_OK; +} + +static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, ULONG ulStringType, + LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static IInternetBindInfoVtbl bind_info_vtbl = { + BindInfo_QueryInterface, + BindInfo_AddRef, + BindInfo_Release, + BindInfo_GetBindInfo, + BindInfo_GetBindString +}; + +static IInternetBindInfo bind_info = { &bind_info_vtbl }; + +static void file_protocol_start(IInternetProtocol *protocol, LPCWSTR url, BOOL is_first) +{ + HRESULT hres; + + SET_EXPECT(GetBindInfo); + SET_EXPECT(ReportProgress_DIRECTBIND); + if(is_first) { + SET_EXPECT(ReportProgress_CACHEFILENAMEAVAILABLE); + SET_EXPECT(ReportProgress_MIMETYPEAVAILABLE); + SET_EXPECT(ReportResult); + } + SET_EXPECT(ReportData); + expect_hrResult = S_OK; + + hres = IInternetProtocol_Start(protocol, url, &protocol_sink, &bind_info, 0, 0); + ok(hres == S_OK, "Start failed: %08lx\n", hres); + + CHECK_CALLED(GetBindInfo); + todo_wine { CHECK_CALLED(ReportProgress_DIRECTBIND); } + if(is_first) { + CHECK_CALLED(ReportProgress_CACHEFILENAMEAVAILABLE); + todo_wine { CHECK_CALLED(ReportProgress_MIMETYPEAVAILABLE); } + CHECK_CALLED(ReportResult); + } + CHECK_CALLED(ReportData); +} + +static void test_file_protocol_url(LPCWSTR url) +{ + IInternetProtocolInfo *protocol_info; + IUnknown *unk; + IClassFactory *factory; + HRESULT hres; + + hres = CoGetClassObject(&CLSID_FileProtocol, CLSCTX_INPROC_SERVER, NULL, + &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "CoGetClassObject failed: %08lx\n", hres); + if(!SUCCEEDED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); + ok(hres == E_NOINTERFACE, + "Could not get IInternetProtocolInfo interface: %08lx, expected E_NOINTERFACE\n", hres); + + hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&factory); + ok(hres == S_OK, "Could not get IClassFactory interface\n"); + if(SUCCEEDED(hres)) { + IInternetProtocol *protocol; + BYTE buf[512]; + ULONG cb; + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres); + + if(SUCCEEDED(hres)) { + file_protocol_start(protocol, url, TRUE); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_OK, "Read failed: %08lx\n", hres); + ok(cb == 2, "cb=%lu expected 2\n", cb); + hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb); + ok(hres == S_FALSE, "Read failed: %08lx\n", hres); + hres = IInternetProtocol_Read(protocol, buf, sizeof(buf), &cb); + ok(hres == S_FALSE, "Read failed: %08lx expected S_FALSE\n", hres); + ok(cb == 0, "cb=%lu expected 0\n", cb); + hres = IInternetProtocol_UnlockRequest(protocol); + ok(hres == S_OK, "UnlockRequest failed: %08lx\n", hres); + + file_protocol_start(protocol, url, FALSE); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_FALSE, "Read failed: %08lx\n", hres); + hres = IInternetProtocol_LockRequest(protocol, 0); + ok(hres == S_OK, "LockRequest failed: %08lx\n", hres); + hres = IInternetProtocol_UnlockRequest(protocol); + ok(hres == S_OK, "UnlockRequest failed: %08lx\n", hres); + + IInternetProtocol_Release(protocol); + } + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres); + + if(SUCCEEDED(hres)) { + file_protocol_start(protocol, url, TRUE); + hres = IInternetProtocol_LockRequest(protocol, 0); + ok(hres == S_OK, "LockRequest failed: %08lx\n", hres); + hres = IInternetProtocol_Terminate(protocol, 0); + ok(hres == S_OK, "Terminate failed: %08lx\n", hres); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_OK, "Read failed: %08lx\n\n", hres); + hres = IInternetProtocol_UnlockRequest(protocol); + ok(hres == S_OK, "UnlockRequest failed: %08lx\n", hres); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_OK, "Read failed: %08lx\n", hres); + hres = IInternetProtocol_Terminate(protocol, 0); + ok(hres == S_OK, "Terminate failed: %08lx\n", hres); + + IInternetProtocol_Release(protocol); + } + + hres = IClassFactory_CreateInstance(factory, NULL, &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "Could not get IInternetProtocol: %08lx\n", hres); + + if(SUCCEEDED(hres)) { + file_protocol_start(protocol, url, TRUE); + hres = IInternetProtocol_Terminate(protocol, 0); + ok(hres == S_OK, "Terminate failed: %08lx\n", hres); + hres = IInternetProtocol_Read(protocol, buf, 2, &cb); + ok(hres == S_OK, "Read failed: %08lx\n", hres); + ok(cb == 2, "cb=%lu expected 2\n", cb); + + IInternetProtocol_Release(protocol); + } + + IClassFactory_Release(factory); + } + + IUnknown_Release(unk); +} + +static void test_file_protocol(void) { + IInternetProtocol *protocol; + WCHAR buf[MAX_PATH]; + ULONG len; + HANDLE file; + HRESULT hres; + + static const WCHAR index_url[] = + {'f','i','l','e',':','i','n','d','e','x','.','h','t','m','l',0}; + static const WCHAR index_url2[] = + {'f','i','l','e',':','/','/','i','n','d','e','x','.','h','t','m','l',0}; + static const WCHAR wszFile[] = {'f','i','l','e',':',0}; + static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0}; + static const char html_doc[] = ""; + + file = CreateFileW(wszIndexHtml, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != NULL, "CreateFile failed\n"); + if(!file) + return; + WriteFile(file, html_doc, sizeof(html_doc)-1, NULL, NULL); + CloseHandle(file); + + file_name = wszIndexHtml; + test_file_protocol_url(index_url); + + memcpy(buf, wszFile, sizeof(wszFile)); + len = sizeof(wszFile)/sizeof(WCHAR)-1; + len += GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR)-len, buf+len); + buf[len++] = '\\'; + memcpy(buf+len, wszIndexHtml, sizeof(wszIndexHtml)); + + file_name = buf + sizeof(wszFile)/sizeof(WCHAR)-1; + test_file_protocol_url(buf); + + DeleteFileW(wszIndexHtml); + + hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "CoCreateInstance failed: %08lx\n", hres); + if(FAILED(hres)) + return; + + SET_EXPECT(GetBindInfo); + expect_hrResult = MK_E_SYNTAX; + hres = IInternetProtocol_Start(protocol, wszIndexHtml, &protocol_sink, &bind_info, 0, 0); + ok(hres == MK_E_SYNTAX, "Start failed: %08lx, expected MK_E_SYNTAX\n", hres); + CHECK_CALLED(GetBindInfo); + + SET_EXPECT(GetBindInfo); + SET_EXPECT(ReportProgress_DIRECTBIND); + SET_EXPECT(ReportResult); + expect_hrResult = INET_E_RESOURCE_NOT_FOUND; + hres = IInternetProtocol_Start(protocol, index_url, &protocol_sink, &bind_info, 0, 0); + ok(hres == INET_E_RESOURCE_NOT_FOUND, + "Start failed: %08lx expected INET_E_RESOURCE_NOT_FOUND\n", hres); + CHECK_CALLED(GetBindInfo); + todo_wine { CHECK_CALLED(ReportProgress_DIRECTBIND); } + CHECK_CALLED(ReportResult); + + IInternetProtocol_Release(protocol); + + hres = CoCreateInstance(&CLSID_FileProtocol, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IInternetProtocol, (void**)&protocol); + ok(hres == S_OK, "CoCreateInstance failed: %08lx\n", hres); + if(FAILED(hres)) + return; + + SET_EXPECT(GetBindInfo); + SET_EXPECT(ReportProgress_DIRECTBIND); + SET_EXPECT(ReportResult); + expect_hrResult = INET_E_RESOURCE_NOT_FOUND; + hres = IInternetProtocol_Start(protocol, index_url2, &protocol_sink, &bind_info, 0, 0); + ok(hres == INET_E_RESOURCE_NOT_FOUND, + "Start failed: %08lx, expected INET_E_RESOURCE_NOT_FOUND\n", hres); + CHECK_CALLED(GetBindInfo); + todo_wine { CHECK_CALLED(ReportProgress_DIRECTBIND); } + CHECK_CALLED(ReportResult); + + IInternetProtocol_Release(protocol); +} + +START_TEST(protocol) +{ + OleInitialize(NULL); + + test_file_protocol(); + + OleUninitialize(); +} diff --git a/dlls/urlmon/urlmon_main.c b/dlls/urlmon/urlmon_main.c index 3dcda86e451..d299afd642b 100644 --- a/dlls/urlmon/urlmon_main.c +++ b/dlls/urlmon/urlmon_main.c @@ -101,6 +101,7 @@ struct object_creation_info static const struct object_creation_info object_creation[] = { + { &CLSID_FileProtocol, FileProtocol_Construct }, { &CLSID_InternetSecurityManager, &SecManagerImpl_Construct }, { &CLSID_InternetZoneManager, ZoneMgrImpl_Construct } }; diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h index 3c912f78c8f..26aa5226801 100644 --- a/dlls/urlmon/urlmon_main.h +++ b/dlls/urlmon/urlmon_main.h @@ -27,6 +27,7 @@ extern HINSTANCE URLMON_hInstance; extern HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); extern HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); +extern HRESULT FileProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); /********************************************************************** * Dll lifetime tracking declaration for urlmon.dll @@ -36,6 +37,7 @@ static inline void URLMON_LockModule(void) { InterlockedIncrement( &URLMON_refCo static inline void URLMON_UnlockModule(void) { InterlockedDecrement( &URLMON_refCount ); } #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) +#define DEFINE_THIS(cls,ifc,iface) ((cls*)((BYTE*)(iface)-offsetof(cls,lp ## ifc ## Vtbl))) typedef struct {