]> git.saurik.com Git - wxWidgets.git/commitdiff
Implement basic support for virtual file systems for the ie backend. Registering...
authorSteve Lamerton <steve.lamerton@gmail.com>
Fri, 22 Jul 2011 12:31:18 +0000 (12:31 +0000)
committerSteve Lamerton <steve.lamerton@gmail.com>
Fri, 22 Jul 2011 12:31:18 +0000 (12:31 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/SOC2011_WEBVIEW@68326 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/msw/webview_ie.h
src/msw/webview_ie.cpp

index ebf325cc444e44057ca83fea68f0149559b73a1b..83e2b6c14bef74856e689a3e1c04dc8c8697eda0 100644 (file)
@@ -23,6 +23,9 @@
 
 struct IHTMLDocument2;
 
+class wxFSFile;
+class wxFileSystem;
+
 class WXDLLIMPEXP_WEB wxWebViewIE : public wxWebView
 {
 public:
@@ -157,6 +160,65 @@ private:
 
 };
 
+class VirtualProtocol : public IInternetProtocol
+{
+protected:
+    ULONG m_refCount;
+    IInternetProtocolSink* m_protocolSink;
+    wxString m_html;
+    VOID * fileP;
+
+    wxFSFile* m_file;
+    wxFileSystem* m_fileSys;
+
+public:
+    VirtualProtocol();
+    ~VirtualProtocol();
+
+    //IUnknown
+    ULONG STDMETHODCALLTYPE AddRef();
+    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+    ULONG STDMETHODCALLTYPE Release();
+
+    //IInternetProtocolRoot
+    HRESULT STDMETHODCALLTYPE Abort(HRESULT hrReason, DWORD dwOptions)
+                                   { return E_NOTIMPL; }
+    HRESULT STDMETHODCALLTYPE Continue(PROTOCOLDATA *pProtocolData)
+                                       { return S_OK; }
+    HRESULT STDMETHODCALLTYPE Resume() { return S_OK; }
+    HRESULT STDMETHODCALLTYPE Start(LPCWSTR szUrl, 
+                                    IInternetProtocolSink *pOIProtSink,
+                                    IInternetBindInfo *pOIBindInfo, 
+                                    DWORD grfPI, 
+                                    HANDLE_PTR dwReserved);
+    HRESULT STDMETHODCALLTYPE Suspend() { return S_OK; }
+    HRESULT STDMETHODCALLTYPE Terminate(DWORD dwOptions) { return S_OK; }
+
+    //IInternetProtocol
+    HRESULT STDMETHODCALLTYPE LockRequest(DWORD dwOptions) { return S_OK; }
+    HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead);
+    HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, 
+                                   ULARGE_INTEGER* plibNewPosition) 
+                                   { return E_FAIL; }
+    HRESULT STDMETHODCALLTYPE UnlockRequest() { return S_OK; }
+};
+
+class ClassFactory : public IClassFactory
+{
+private:
+    ULONG m_refCount;
+public:
+    //IUnknown
+    ULONG STDMETHODCALLTYPE AddRef();
+    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+    ULONG STDMETHODCALLTYPE Release();
+
+    //IClassFactory
+    HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown* pUnkOuter, 
+                                             REFIID riid, void** ppvObject);
+    HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock);
+};
+
 #endif // wxUSE_WEBVIEW_IE
 
 #endif // wxWebViewIE_H
index 78e069dd2f4d9424caa5a921eb09022bc2f88d90..cfe3bfaa04b5388d4f856b88932e7456794f7536 100644 (file)
 #include <mshtml.h>
 #include "wx/msw/registry.h"
 #include "wx/msw/missing.h"
+#include "wx/filesys.h"
+
+//Taken from wx/filesys.cpp
+static wxString EscapeFileNameCharsInURL(const char *in)
+{
+    wxString s;
+
+    for ( const unsigned char *p = (const unsigned char*)in; *p; ++p )
+    {
+        const unsigned char c = *p;
+
+        if ( c == '/' || c == '-' || c == '.' || c == '_' || c == '~' ||
+             (c >= '0' && c <= '9') ||
+             (c >= 'a' && c <= 'z') ||
+             (c >= 'A' && c <= 'Z') )
+        {
+            s << c;
+        }
+        else
+        {
+            s << wxString::Format("%%%02x", c);
+        }
+    }
+
+    return s;
+}
 
 BEGIN_EVENT_TABLE(wxWebViewIE, wxControl)
     EVT_ACTIVEX(wxID_ANY, wxWebViewIE::onActiveXEvent)
@@ -68,6 +94,16 @@ bool wxWebViewIE::Create(wxWindow* parent,
     m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
     //m_webBrowser->put_Silent(VARIANT_FALSE);
 
+    //We register a custom handler for the file protocol so we can handle
+    //Virtual file systems
+    ClassFactory* cf = new ClassFactory;
+    IInternetSession* session;
+    if(CoInternetGetSession(0, &session, 0) != S_OK)
+        return false;
+    HRESULT hr = session->RegisterNameSpace(cf, CLSID_FileProtocol, L"file", 0, NULL, 0);
+    if(FAILED(hr))
+        return false; 
+
     m_container = new wxActiveXContainer(this, IID_IWebBrowser2, m_webBrowser);
 
     SetBackgroundStyle(wxBG_STYLE_PAINT);
@@ -950,4 +986,166 @@ void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt)
     evt.Skip();
 }
 
+VirtualProtocol::VirtualProtocol()
+{
+    m_refCount = 0;
+    m_file = NULL;
+    m_fileSys = new wxFileSystem;
+}
+
+VirtualProtocol::~VirtualProtocol()
+{
+    wxDELETE(m_fileSys);
+}
+
+ULONG VirtualProtocol::AddRef()
+{
+    m_refCount++;
+    return m_refCount;
+}
+
+HRESULT VirtualProtocol::QueryInterface(REFIID riid, void **ppvObject)
+{
+    if ((riid == IID_IUnknown) || (riid == IID_IInternetProtocol)
+       || (riid == IID_IInternetProtocolRoot))
+    {
+        *ppvObject = this;
+        AddRef();
+        return S_OK;
+    }
+    else
+    {
+        *ppvObject = NULL;
+        return E_POINTER;
+    }
+}
+
+ULONG VirtualProtocol::Release()
+{
+    m_refCount--;
+    if (m_refCount > 0)
+    {
+        return m_refCount;
+    }
+    else
+    {
+        delete this;
+        return 0;
+    }
+}
+
+HRESULT VirtualProtocol::Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink,
+                            IInternetBindInfo *pOIBindInfo, DWORD grfPI, 
+                            HANDLE_PTR dwReserved)
+{
+    m_protocolSink = pOIProtSink;
+    //We have to clean up incoming paths from the webview control as they are
+    //not properly escaped, see also the comment in filesys.cpp line 668
+    wxString path = wxString(szUrl).BeforeFirst(':') +  ":" + 
+                    EscapeFileNameCharsInURL(wxString(szUrl).AfterFirst(':'));
+    path.Replace("///", "/");
+    m_file = m_fileSys->OpenFile(path);
+
+    if(!m_file)
+        return INET_E_RESOURCE_NOT_FOUND;
+
+    //We return the stream length for current and total size as we can always
+    //read the whole file from the stream
+    m_protocolSink->ReportData(BSCF_FIRSTDATANOTIFICATION | 
+                               BSCF_DATAFULLYAVAILABLE |
+                               BSCF_LASTDATANOTIFICATION,
+                               m_file->GetStream()->GetLength(),
+                               m_file->GetStream()->GetLength());
+    return S_OK; 
+}
+
+HRESULT VirtualProtocol::Read(void *pv, ULONG cb, ULONG *pcbRead)
+{
+    //If the file is null we return false to indicte it is finished
+    if(!m_file) 
+        return S_FALSE;
+
+    wxStreamError err = m_file->GetStream()->Read(pv, cb).GetLastError();
+    *pcbRead = m_file->GetStream()->LastRead();
+
+    if(err == wxSTREAM_NO_ERROR)
+    {
+        if(*pcbRead < cb)
+        {
+            wxDELETE(m_file);
+            m_protocolSink->ReportResult(S_OK, 0, NULL);
+        }
+        //As we are not eof there is more data
+        return S_OK;
+    }
+    else if(err == wxSTREAM_EOF)
+    {
+        wxDELETE(m_file);
+        m_protocolSink->ReportResult(S_OK, 0, NULL);
+        //We are eof and so finished
+        return S_OK;
+    }
+    else if(err ==  wxSTREAM_READ_ERROR)
+    {
+        wxDELETE(m_file);
+        return INET_E_DOWNLOAD_FAILURE;
+    }
+}
+
+HRESULT ClassFactory::CreateInstance(IUnknown* pUnkOuter, REFIID riid,
+                                     void ** ppvObject)
+{
+    if (pUnkOuter) 
+        return CLASS_E_NOAGGREGATION;
+    VirtualProtocol* vp = new VirtualProtocol;
+    vp->AddRef();
+    HRESULT hr = vp->QueryInterface(riid, ppvObject);
+    vp->Release();
+    return hr;
+
+} 
+
+STDMETHODIMP ClassFactory::LockServer(BOOL fLock)
+{
+     return S_OK;
+
+}
+
+ULONG ClassFactory::AddRef(void)
+{
+    m_refCount++;
+    return m_refCount;
+}
+
+HRESULT ClassFactory::QueryInterface(REFIID riid, void **ppvObject)
+{
+    if ((riid == IID_IUnknown) || (riid == IID_IClassFactory))
+    {
+        *ppvObject = this;
+        AddRef();
+        return S_OK;
+    }
+    else
+    {
+        *ppvObject = NULL;
+        return E_POINTER;
+    }
+
+}
+
+ULONG ClassFactory::Release(void)
+{
+    m_refCount--;
+    if (m_refCount > 0)
+    {
+        return m_refCount;
+    }
+    else
+    {
+        delete this;
+        return 0;
+    }
+
+} 
+
 #endif