URLMON: Added file protocol implementation

Jacek Caban jack at itma.pwr.wroc.pl
Sat Sep 3 14:22:52 CDT 2005


Changelog:
    Added file protocol implementation
-------------- next part --------------
? dlls/urlmon/file.c
? dlls/urlmon/tests/protocol.c
? dlls/urlmon/tests/protocol.ok
Index: dlls/urlmon/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/urlmon/Makefile.in,v
retrieving revision 1.26
diff -u -p -r1.26 Makefile.in
--- dlls/urlmon/Makefile.in	2 Sep 2005 12:17:30 -0000	1.26
+++ dlls/urlmon/Makefile.in	3 Sep 2005 17:19:23 -0000
@@ -8,6 +8,7 @@ IMPORTS   = cabinet ole32 shlwapi winine
 EXTRALIBS = -luuid
 
 C_SRCS = \
+	file.c \
 	format.c \
 	regsvr.c \
 	sec_mgr.c \
Index: dlls/urlmon/urlmon_main.c
===================================================================
RCS file: /home/wine/wine/dlls/urlmon/urlmon_main.c,v
retrieving revision 1.31
diff -u -p -r1.31 urlmon_main.c
--- dlls/urlmon/urlmon_main.c	8 Aug 2005 17:37:40 -0000	1.31
+++ dlls/urlmon/urlmon_main.c	3 Sep 2005 17:19:23 -0000
@@ -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 }
 };
Index: dlls/urlmon/urlmon_main.h
===================================================================
RCS file: /home/wine/wine/dlls/urlmon/urlmon_main.h,v
retrieving revision 1.11
diff -u -p -r1.11 urlmon_main.h
--- dlls/urlmon/urlmon_main.h	5 Jul 2005 14:06:43 -0000	1.11
+++ dlls/urlmon/urlmon_main.h	3 Sep 2005 17:19:23 -0000
@@ -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(voi
 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
 {	
Index: dlls/urlmon/tests/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/urlmon/tests/Makefile.in,v
retrieving revision 1.6
diff -u -p -r1.6 Makefile.in
--- dlls/urlmon/tests/Makefile.in	3 Sep 2005 09:36:12 -0000	1.6
+++ dlls/urlmon/tests/Makefile.in	3 Sep 2005 17:19:23 -0000
@@ -9,6 +9,7 @@ EXTRALIBS = -luuid
 CTESTS = \
 	generated.c \
 	misc.c \
+	protocol.c \
 	url.c
 
 @MAKE_TEST_RULES@
--- /dev/null	2005-09-03 09:18:53.484530250 +0000
+++ dlls/urlmon/file.c	2005-09-03 19:18:25.000000000 +0000
@@ -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 <stdarg.h>
+
+#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;
+}
--- /dev/null	2005-09-03 09:18:53.484530250 +0000
+++ dlls/urlmon/tests/protocol.c	2005-09-03 19:21:29.000000000 +0000
@@ -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 <wine/test.h>
+#include <stdarg.h>
+
+#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[] = "<HTML></HTML>";
+
+    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();
+}


More information about the wine-patches mailing list