/* * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include <stdarg.h> #include <stdio.h> #define COBJMACROS #include "windef.h" #include "winbase.h" #include "winuser.h" #include "ole2.h" #include "wine/debug.h" #include "mshtml_private.h" WINE_DEFAULT_DEBUG_CHANNEL(mshtml); typedef struct { IUnknown IUnknown_inner; IInternetProtocol IInternetProtocol_iface; LONG ref; BYTE *data; ULONG data_len; ULONG cur; IUnknown *outer; } InternetProtocol; /******************************************************************** * common ProtocolFactory implementation */ typedef struct { IInternetProtocolInfo IInternetProtocolInfo_iface; IClassFactory IClassFactory_iface; } ProtocolFactory; static inline ProtocolFactory *impl_from_IInternetProtocolInfo(IInternetProtocolInfo *iface) { return CONTAINING_RECORD(iface, ProtocolFactory, IInternetProtocolInfo_iface); } static HRESULT WINAPI InternetProtocolInfo_QueryInterface(IInternetProtocolInfo *iface, REFIID riid, void **ppv) { ProtocolFactory *This = impl_from_IInternetProtocolInfo(iface); *ppv = NULL; if(IsEqualGUID(&IID_IUnknown, riid)) { TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); *ppv = &This->IInternetProtocolInfo_iface; }else if(IsEqualGUID(&IID_IInternetProtocolInfo, riid)) { TRACE("(%p)->(IID_IInternetProtocolInfo %p)\n", This, ppv); *ppv = &This->IInternetProtocolInfo_iface; }else if(IsEqualGUID(&IID_IClassFactory, riid)) { TRACE("(%p)->(IID_IClassFactory %p)\n", This, ppv); *ppv = &This->IClassFactory_iface; } if(!*ppv) { WARN("unknown interface %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } IInternetProtocolInfo_AddRef(iface); return S_OK; } static ULONG WINAPI InternetProtocolInfo_AddRef(IInternetProtocolInfo *iface) { TRACE("(%p)\n", iface); return 2; } static ULONG WINAPI InternetProtocolInfo_Release(IInternetProtocolInfo *iface) { TRACE("(%p)\n", iface); return 1; } static HRESULT WINAPI InternetProtocolInfo_CombineUrl(IInternetProtocolInfo *iface, LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult, DWORD* pcchResult, DWORD dwReserved) { TRACE("%p)->(%s %s %08x %p %d %p %d)\n", iface, debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved); return INET_E_USE_DEFAULT_PROTOCOLHANDLER; } static HRESULT WINAPI InternetProtocolInfo_CompareUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCompareFlags) { TRACE("%p)->(%s %s %08x)\n", iface, debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags); return E_NOTIMPL; } static inline ProtocolFactory *impl_from_IClassFactory(IClassFactory *iface) { return CONTAINING_RECORD(iface, ProtocolFactory, IClassFactory_iface); } static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) { ProtocolFactory *This = impl_from_IClassFactory(iface); return IInternetProtocolInfo_QueryInterface(&This->IInternetProtocolInfo_iface, riid, ppv); } static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { ProtocolFactory *This = impl_from_IClassFactory(iface); return IInternetProtocolInfo_AddRef(&This->IInternetProtocolInfo_iface); } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { ProtocolFactory *This = impl_from_IClassFactory(iface); return IInternetProtocolInfo_Release(&This->IInternetProtocolInfo_iface); } static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) { TRACE("(%p)->(%x)\n", iface, dolock); return S_OK; } static inline InternetProtocol *impl_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, InternetProtocol, IUnknown_inner); } static inline InternetProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface) { return CONTAINING_RECORD(iface, InternetProtocol, IInternetProtocol_iface); } static HRESULT WINAPI Protocol_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) { InternetProtocol *This = impl_from_IUnknown(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); if(IsEqualGUID(&IID_IUnknown, riid)) { *ppv = &This->IUnknown_inner; }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) { *ppv = &This->IInternetProtocol_iface; }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) { *ppv = &This->IInternetProtocol_iface; }else { if(IsEqualGUID(&IID_IServiceProvider, riid)) FIXME("IServiceProvider is not implemented\n"); *ppv = NULL; return E_NOINTERFACE; } IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } static ULONG WINAPI Protocol_AddRef(IUnknown *iface) { InternetProtocol *This = impl_from_IUnknown(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", iface, ref); return ref; } static ULONG WINAPI Protocol_Release(IUnknown *iface) { InternetProtocol *This = impl_from_IUnknown(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%x\n", iface, ref); if(!ref) { heap_free(This->data); heap_free(This); } return ref; } static const IUnknownVtbl ProtocolUnkVtbl = { Protocol_QueryInterface, Protocol_AddRef, Protocol_Release }; static HRESULT WINAPI InternetProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) { InternetProtocol *This = impl_from_IInternetProtocol(iface); return IUnknown_QueryInterface(This->outer, riid, ppv); } static ULONG WINAPI InternetProtocol_AddRef(IInternetProtocol *iface) { InternetProtocol *This = impl_from_IInternetProtocol(iface); return IUnknown_AddRef(This->outer); } static ULONG WINAPI InternetProtocol_Release(IInternetProtocol *iface) { InternetProtocol *This = impl_from_IInternetProtocol(iface); return IUnknown_Release(This->outer); } static HRESULT WINAPI InternetProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA* pProtocolData) { InternetProtocol *This = impl_from_IInternetProtocol(iface); FIXME("(%p)->(%p)\n", This, pProtocolData); return E_NOTIMPL; } static HRESULT WINAPI InternetProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, DWORD dwOptions) { InternetProtocol *This = impl_from_IInternetProtocol(iface); FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); return E_NOTIMPL; } static HRESULT WINAPI InternetProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) { InternetProtocol *This = impl_from_IInternetProtocol(iface); TRACE("(%p)->(%08x)\n", This, dwOptions); return S_OK; } static HRESULT WINAPI InternetProtocol_Suspend(IInternetProtocol *iface) { InternetProtocol *This = impl_from_IInternetProtocol(iface); FIXME("(%p)\n", This); return E_NOTIMPL; } static HRESULT WINAPI InternetProtocol_Resume(IInternetProtocol *iface) { InternetProtocol *This = impl_from_IInternetProtocol(iface); FIXME("(%p)\n", This); return E_NOTIMPL; } static HRESULT WINAPI InternetProtocol_Read(IInternetProtocol *iface, void* pv, ULONG cb, ULONG* pcbRead) { InternetProtocol *This = impl_from_IInternetProtocol(iface); TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); if(!This->data) return E_FAIL; *pcbRead = (cb > This->data_len-This->cur ? This->data_len-This->cur : cb); if(!*pcbRead) return S_FALSE; memcpy(pv, This->data+This->cur, *pcbRead); This->cur += *pcbRead; return S_OK; } static HRESULT WINAPI InternetProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { InternetProtocol *This = impl_from_IInternetProtocol(iface); FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); return E_NOTIMPL; } static HRESULT WINAPI InternetProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) { InternetProtocol *This = impl_from_IInternetProtocol(iface); TRACE("(%p)->(%d)\n", This, dwOptions); return S_OK; } static HRESULT WINAPI InternetProtocol_UnlockRequest(IInternetProtocol *iface) { InternetProtocol *This = impl_from_IInternetProtocol(iface); TRACE("(%p)\n", This); return S_OK; } static HRESULT create_protocol_instance(const IInternetProtocolVtbl *protocol_vtbl, IUnknown *outer, REFIID riid, void **ppv) { InternetProtocol *protocol; HRESULT hres; if(outer && !IsEqualGUID(&IID_IUnknown, riid)) { *ppv = NULL; return E_INVALIDARG; } protocol = heap_alloc_zero(sizeof(InternetProtocol)); protocol->IUnknown_inner.lpVtbl = &ProtocolUnkVtbl; protocol->IInternetProtocol_iface.lpVtbl = protocol_vtbl; protocol->outer = outer ? outer : &protocol->IUnknown_inner; protocol->ref = 1; hres = IUnknown_QueryInterface(&protocol->IUnknown_inner, riid, ppv); IUnknown_Release(&protocol->IUnknown_inner); return hres; } /******************************************************************** * about protocol implementation */ static HRESULT WINAPI AboutProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved) { InternetProtocol *This = impl_from_IInternetProtocol(iface); BINDINFO bindinfo; DWORD grfBINDF = 0; LPCWSTR text = NULL; DWORD data_len; BYTE *data; HRESULT hres; static const WCHAR html_begin[] = {0xfeff,'<','H','T','M','L','>',0}; static const WCHAR html_end[] = {'<','/','H','T','M','L','>',0}; static const WCHAR wszBlank[] = {'b','l','a','n','k',0}; static const WCHAR wszAbout[] = {'a','b','o','u','t',':'}; static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0}; /* NOTE: * the about protocol seems not to work as I would expect. It creates html document * for a given url, eg. about:some_text -> <HTML>some_text</HTML> except for the case when * some_text = "blank", when document is blank (<HTML></HMTL>). The same happens * when the url does not have "about:" in the beginning. */ TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved); memset(&bindinfo, 0, sizeof(bindinfo)); bindinfo.cbSize = sizeof(BINDINFO); hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo); if(FAILED(hres)) return hres; ReleaseBindInfo(&bindinfo); TRACE("bindf %x\n", grfBINDF); if(lstrlenW(szUrl) >= ARRAY_SIZE(wszAbout) && !memcmp(wszAbout, szUrl, sizeof(wszAbout))) { text = szUrl + ARRAY_SIZE(wszAbout); if(!wcscmp(wszBlank, text)) text = NULL; } data_len = sizeof(html_begin)+sizeof(html_end)-sizeof(WCHAR) + (text ? lstrlenW(text)*sizeof(WCHAR) : 0); data = heap_alloc(data_len); if(!data) return E_OUTOFMEMORY; heap_free(This->data); This->data = data; This->data_len = data_len; memcpy(This->data, html_begin, sizeof(html_begin)); if(text) lstrcatW((LPWSTR)This->data, text); lstrcatW((LPWSTR)This->data, html_end); This->cur = 0; IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, wszTextHtml); IInternetProtocolSink_ReportData(pOIProtSink, BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, This->data_len, This->data_len); IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL); return S_OK; } static const IInternetProtocolVtbl AboutProtocolVtbl = { InternetProtocol_QueryInterface, InternetProtocol_AddRef, InternetProtocol_Release, AboutProtocol_Start, InternetProtocol_Continue, InternetProtocol_Abort, InternetProtocol_Terminate, InternetProtocol_Suspend, InternetProtocol_Resume, InternetProtocol_Read, InternetProtocol_Seek, InternetProtocol_LockRequest, InternetProtocol_UnlockRequest }; static HRESULT WINAPI AboutProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv) { TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv); return create_protocol_instance(&AboutProtocolVtbl, pUnkOuter, riid, ppv); } static HRESULT WINAPI AboutProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, DWORD* pcchResult, DWORD dwReserved) { TRACE("%p)->(%s %d %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), ParseAction, dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved); if(ParseAction == PARSE_SECURITY_URL) { unsigned int len = lstrlenW(pwzUrl)+1; *pcchResult = len; if(len > cchResult) return S_FALSE; memcpy(pwzResult, pwzUrl, len*sizeof(WCHAR)); return S_OK; } if(ParseAction == PARSE_DOMAIN) { if(!pcchResult) return E_POINTER; if(pwzUrl) *pcchResult = lstrlenW(pwzUrl)+1; else *pcchResult = 1; return E_FAIL; } return INET_E_DEFAULT_ACTION; } static HRESULT WINAPI AboutProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf, DWORD dwReserved) { TRACE("%p)->(%s %08x %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer, cbBuffer, pcbBuf, dwReserved); switch(QueryOption) { case QUERY_CAN_NAVIGATE: return INET_E_USE_DEFAULT_PROTOCOLHANDLER; case QUERY_USES_NETWORK: if(!pBuffer || cbBuffer < sizeof(DWORD)) return E_FAIL; *(DWORD*)pBuffer = 0; if(pcbBuf) *pcbBuf = sizeof(DWORD); break; case QUERY_IS_CACHED: FIXME("Unsupported option QUERY_IS_CACHED\n"); return E_NOTIMPL; case QUERY_IS_INSTALLEDENTRY: FIXME("Unsupported option QUERY_IS_INSTALLEDENTRY\n"); return E_NOTIMPL; case QUERY_IS_CACHED_OR_MAPPED: FIXME("Unsupported option QUERY_IS_CACHED_OR_MAPPED\n"); return E_NOTIMPL; case QUERY_IS_SECURE: FIXME("Unsupported option QUERY_IS_SECURE\n"); return E_NOTIMPL; case QUERY_IS_SAFE: FIXME("Unsupported option QUERY_IS_SAFE\n"); return E_NOTIMPL; case QUERY_USES_HISTORYFOLDER: FIXME("Unsupported option QUERY_USES_HISTORYFOLDER\n"); return E_FAIL; case QUERY_IS_CACHED_AND_USABLE_OFFLINE: FIXME("Unsupported option QUERY_IS_CACHED_AND_USABLE_OFFLINE\n"); return E_NOTIMPL; default: return E_FAIL; } return S_OK; } static const IInternetProtocolInfoVtbl AboutProtocolInfoVtbl = { InternetProtocolInfo_QueryInterface, InternetProtocolInfo_AddRef, InternetProtocolInfo_Release, AboutProtocolInfo_ParseUrl, InternetProtocolInfo_CombineUrl, InternetProtocolInfo_CompareUrl, AboutProtocolInfo_QueryInfo }; static const IClassFactoryVtbl AboutProtocolFactoryVtbl = { ClassFactory_QueryInterface, ClassFactory_AddRef, ClassFactory_Release, AboutProtocolFactory_CreateInstance, ClassFactory_LockServer }; static ProtocolFactory AboutProtocolFactory = { { &AboutProtocolInfoVtbl }, { &AboutProtocolFactoryVtbl } }; /******************************************************************** * res protocol implementation */ static HRESULT WINAPI ResProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, IInternetProtocolSink* pOIProtSink, IInternetBindInfo* pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved) { InternetProtocol *This = impl_from_IInternetProtocol(iface); WCHAR *url_dll, *url_file, *url, *mime, *res_type, *alt_res_type = NULL, *ptr; DWORD grfBINDF = 0, len; BINDINFO bindinfo; HMODULE hdll; HRSRC src; HRESULT hres; static const WCHAR wszRes[] = {'r','e','s',':','/','/'}; TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved); memset(&bindinfo, 0, sizeof(bindinfo)); bindinfo.cbSize = sizeof(BINDINFO); hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo); if(FAILED(hres)) return hres; ReleaseBindInfo(&bindinfo); len = lstrlenW(szUrl)+16; url = heap_alloc(len*sizeof(WCHAR)); hres = CoInternetParseUrl(szUrl, PARSE_ENCODE, 0, url, len, &len, 0); if(FAILED(hres)) { WARN("CoInternetParseUrl failed: %08x\n", hres); heap_free(url); IInternetProtocolSink_ReportResult(pOIProtSink, hres, 0, NULL); return hres; } if(len < ARRAY_SIZE(wszRes) || memcmp(url, wszRes, sizeof(wszRes))) { WARN("Wrong protocol of url: %s\n", debugstr_w(url)); IInternetProtocolSink_ReportResult(pOIProtSink, E_INVALIDARG, 0, NULL); heap_free(url); return E_INVALIDARG; } url_dll = url + ARRAY_SIZE(wszRes); if(!(res_type = wcschr(url_dll, '/'))) { WARN("wrong url: %s\n", debugstr_w(url)); IInternetProtocolSink_ReportResult(pOIProtSink, MK_E_SYNTAX, 0, NULL); heap_free(url); return MK_E_SYNTAX; } *res_type++ = 0; if ((url_file = wcschr(res_type, '/'))) { DWORD res_type_id; WCHAR *endpoint; *url_file++ = 0; res_type_id = wcstol(res_type, &endpoint, 10); if(!*endpoint) res_type = MAKEINTRESOURCEW(res_type_id); }else { url_file = res_type; res_type = MAKEINTRESOURCEW(RT_HTML); alt_res_type = MAKEINTRESOURCEW(2110 /* RT_FILE */); } /* Ignore query and hash parts. */ if((ptr = wcschr(url_file, '?'))) *ptr = 0; if(*url_file && (ptr = wcschr(url_file+1, '#'))) *ptr = 0; hdll = LoadLibraryExW(url_dll, NULL, LOAD_LIBRARY_AS_DATAFILE); if(!hdll) { WARN("Could not open dll: %s\n", debugstr_w(url_dll)); IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL); heap_free(url); return HRESULT_FROM_WIN32(GetLastError()); } TRACE("trying to find resource type %s, name %s\n", debugstr_w(res_type), debugstr_w(url_file)); src = FindResourceW(hdll, url_file, res_type); if(!src && alt_res_type) src = FindResourceW(hdll, url_file, alt_res_type); if(!src) { LPWSTR endpoint = NULL; DWORD file_id = wcstol(url_file, &endpoint, 10); if(!*endpoint) { src = FindResourceW(hdll, MAKEINTRESOURCEW(file_id), res_type); if(!src && alt_res_type) src = FindResourceW(hdll, MAKEINTRESOURCEW(file_id), alt_res_type); } if(!src) { WARN("Could not find resource\n"); IInternetProtocolSink_ReportResult(pOIProtSink, HRESULT_FROM_WIN32(GetLastError()), 0, NULL); heap_free(url); return HRESULT_FROM_WIN32(GetLastError()); } } if(This->data) { WARN("data already loaded\n"); heap_free(This->data); } This->data_len = SizeofResource(hdll, src); This->data = heap_alloc(This->data_len); memcpy(This->data, LoadResource(hdll, src), This->data_len); This->cur = 0; FreeLibrary(hdll); hres = FindMimeFromData(NULL, url_file, This->data, This->data_len, NULL, 0, &mime, 0); heap_free(url); if(SUCCEEDED(hres)) { IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime); CoTaskMemFree(mime); } IInternetProtocolSink_ReportData(pOIProtSink, BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, This->data_len, This->data_len); IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL); return S_OK; } static const IInternetProtocolVtbl ResProtocolVtbl = { InternetProtocol_QueryInterface, InternetProtocol_AddRef, InternetProtocol_Release, ResProtocol_Start, InternetProtocol_Continue, InternetProtocol_Abort, InternetProtocol_Terminate, InternetProtocol_Suspend, InternetProtocol_Resume, InternetProtocol_Read, InternetProtocol_Seek, InternetProtocol_LockRequest, InternetProtocol_UnlockRequest }; static HRESULT WINAPI ResProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv) { TRACE("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv); return create_protocol_instance(&ResProtocolVtbl, pUnkOuter, riid, ppv); } static HRESULT WINAPI ResProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, DWORD* pcchResult, DWORD dwReserved) { TRACE("%p)->(%s %d %x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), ParseAction, dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved); if(ParseAction == PARSE_SECURITY_URL) { WCHAR file_part[MAX_PATH], full_path[MAX_PATH]; WCHAR *ptr; DWORD size, len; static const WCHAR wszFile[] = {'f','i','l','e',':','/','/'}; static const WCHAR wszRes[] = {'r','e','s',':','/','/'}; if(lstrlenW(pwzUrl) <= ARRAY_SIZE(wszRes) || memcmp(pwzUrl, wszRes, sizeof(wszRes))) return E_INVALIDARG; ptr = wcschr(pwzUrl + ARRAY_SIZE(wszRes), '/'); if(!ptr) return E_INVALIDARG; len = ptr - (pwzUrl + ARRAY_SIZE(wszRes)); if(len >= ARRAY_SIZE(file_part)) { FIXME("Too long URL\n"); return MK_E_SYNTAX; } memcpy(file_part, pwzUrl + ARRAY_SIZE(wszRes), len*sizeof(WCHAR)); file_part[len] = 0; len = SearchPathW(NULL, file_part, NULL, ARRAY_SIZE(full_path), full_path, NULL); if(!len) { HMODULE module; /* SearchPath does not work well with winelib files (like our test executable), * so we also try to load the library here */ module = LoadLibraryExW(file_part, NULL, LOAD_LIBRARY_AS_DATAFILE); if(!module) { WARN("Could not find file %s\n", debugstr_w(file_part)); return MK_E_SYNTAX; } len = GetModuleFileNameW(module, full_path, ARRAY_SIZE(full_path)); FreeLibrary(module); if(!len) return E_FAIL; } size = ARRAY_SIZE(wszFile) + len + 1; if(pcchResult) *pcchResult = size; if(size > cchResult) return S_FALSE; memcpy(pwzResult, wszFile, sizeof(wszFile)); memcpy(pwzResult + ARRAY_SIZE(wszFile), full_path, (len+1)*sizeof(WCHAR)); return S_OK; } if(ParseAction == PARSE_DOMAIN) { if(!pcchResult) return E_POINTER; if(pwzUrl) *pcchResult = lstrlenW(pwzUrl)+1; else *pcchResult = 1; return E_FAIL; } return INET_E_DEFAULT_ACTION; } static HRESULT WINAPI ResProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf, DWORD dwReserved) { TRACE("%p)->(%s %08x %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer, cbBuffer, pcbBuf, dwReserved); switch(QueryOption) { case QUERY_USES_NETWORK: if(!pBuffer || cbBuffer < sizeof(DWORD)) return E_FAIL; *(DWORD*)pBuffer = 0; if(pcbBuf) *pcbBuf = sizeof(DWORD); break; case QUERY_IS_SECURE: FIXME("QUERY_IS_SECURE not supported\n"); return E_NOTIMPL; case QUERY_IS_SAFE: FIXME("QUERY_IS_SAFE not supported\n"); return E_NOTIMPL; default: return INET_E_USE_DEFAULT_PROTOCOLHANDLER; } return S_OK; } static const IInternetProtocolInfoVtbl ResProtocolInfoVtbl = { InternetProtocolInfo_QueryInterface, InternetProtocolInfo_AddRef, InternetProtocolInfo_Release, ResProtocolInfo_ParseUrl, InternetProtocolInfo_CombineUrl, InternetProtocolInfo_CompareUrl, ResProtocolInfo_QueryInfo }; static const IClassFactoryVtbl ResProtocolFactoryVtbl = { ClassFactory_QueryInterface, ClassFactory_AddRef, ClassFactory_Release, ResProtocolFactory_CreateInstance, ClassFactory_LockServer }; static ProtocolFactory ResProtocolFactory = { { &ResProtocolInfoVtbl }, { &ResProtocolFactoryVtbl } }; /******************************************************************** * JSProtocol implementation */ static HRESULT WINAPI JSProtocolFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv) { FIXME("(%p)->(%p %s %p)\n", iface, pUnkOuter, debugstr_guid(riid), ppv); return E_NOTIMPL; } static HRESULT WINAPI JSProtocolInfo_ParseUrl(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, DWORD* pcchResult, DWORD dwReserved) { TRACE("%p)->(%s %d %x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), ParseAction, dwParseFlags, pwzResult, cchResult, pcchResult, dwReserved); switch(ParseAction) { case PARSE_SECURITY_URL: FIXME("PARSE_SECURITY_URL\n"); return E_NOTIMPL; case PARSE_DOMAIN: FIXME("PARSE_DOMAIN\n"); return E_NOTIMPL; default: return INET_E_DEFAULT_ACTION; } return S_OK; } static HRESULT WINAPI JSProtocolInfo_QueryInfo(IInternetProtocolInfo *iface, LPCWSTR pwzUrl, QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD* pcbBuf, DWORD dwReserved) { TRACE("%p)->(%s %08x %08x %p %d %p %d)\n", iface, debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pBuffer, cbBuffer, pcbBuf, dwReserved); switch(QueryOption) { case QUERY_USES_NETWORK: if(!pBuffer || cbBuffer < sizeof(DWORD)) return E_FAIL; *(DWORD*)pBuffer = 0; if(pcbBuf) *pcbBuf = sizeof(DWORD); break; case QUERY_IS_SECURE: FIXME("QUERY_IS_SECURE not supported\n"); return E_NOTIMPL; default: return INET_E_USE_DEFAULT_PROTOCOLHANDLER; } return S_OK; } static const IInternetProtocolInfoVtbl JSProtocolInfoVtbl = { InternetProtocolInfo_QueryInterface, InternetProtocolInfo_AddRef, InternetProtocolInfo_Release, JSProtocolInfo_ParseUrl, InternetProtocolInfo_CombineUrl, InternetProtocolInfo_CompareUrl, JSProtocolInfo_QueryInfo }; static const IClassFactoryVtbl JSProtocolFactoryVtbl = { ClassFactory_QueryInterface, ClassFactory_AddRef, ClassFactory_Release, JSProtocolFactory_CreateInstance, ClassFactory_LockServer }; static ProtocolFactory JSProtocolFactory = { { &JSProtocolInfoVtbl }, { &JSProtocolFactoryVtbl } }; HRESULT ProtocolFactory_Create(REFCLSID rclsid, REFIID riid, void **ppv) { ProtocolFactory *cf = NULL; if(IsEqualGUID(&CLSID_AboutProtocol, rclsid)) cf = &AboutProtocolFactory; else if(IsEqualGUID(&CLSID_ResProtocol, rclsid)) cf = &ResProtocolFactory; else if(IsEqualGUID(&CLSID_JSProtocol, rclsid)) cf = &JSProtocolFactory; if(!cf) { FIXME("not implemented protocol %s\n", debugstr_guid(rclsid)); return CLASS_E_CLASSNOTAVAILABLE; } return IInternetProtocolInfo_QueryInterface(&cf->IInternetProtocolInfo_iface, riid, ppv); }