From: Steve Lamerton Date: Fri, 22 Jul 2011 12:31:18 +0000 (+0000) Subject: Implement basic support for virtual file systems for the ie backend. Registering... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/7d3f6b4ded6aa412cb1cc306fef478955d448c5b?ds=inline Implement basic support for virtual file systems for the ie backend. Registering a temporary namespace allows us to use the existing wxFileSystem work to load virtual files. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/SOC2011_WEBVIEW@68326 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/msw/webview_ie.h b/include/wx/msw/webview_ie.h index ebf325cc44..83e2b6c14b 100644 --- a/include/wx/msw/webview_ie.h +++ b/include/wx/msw/webview_ie.h @@ -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 diff --git a/src/msw/webview_ie.cpp b/src/msw/webview_ie.cpp index 78e069dd2f..cfe3bfaa04 100644 --- a/src/msw/webview_ie.cpp +++ b/src/msw/webview_ie.cpp @@ -25,6 +25,32 @@ #include #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