You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1957 lines
56 KiB
1957 lines
56 KiB
// --------------------------------------------------------------------------------
|
|
// Mhtmlurl.cpp
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// Steven J. Bailey
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "mhtmlurl.h"
|
|
#include "icoint.h"
|
|
#include "dllmain.h"
|
|
#include "booktree.h"
|
|
#include "shlwapi.h"
|
|
#include "shlwapip.h"
|
|
#include <demand.h>
|
|
#include "icdebug.h"
|
|
#include "stmlock.h"
|
|
#include "strconst.h"
|
|
#include "mimeapi.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// TraceProtocol
|
|
// --------------------------------------------------------------------------------
|
|
#define TraceProtocol(_pszFunction) \
|
|
DOUTL(APP_DOUTL, "%08x > 0x%08X CActiveUrlRequest::%s (RootUrl = '%s', BodyUrl = '%s')", GetCurrentThreadId(), this, _pszFunction, m_pszRootUrl ? m_pszRootUrl : "", m_pszBodyUrl ? m_pszBodyUrl : "")
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// AcitveUrlRequest_CreateInstance
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT IMimeHtmlProtocol_CreateInstance(IUnknown *pUnkOuter, IUnknown** ppUnknown)
|
|
{
|
|
// Invalid Arg
|
|
Assert(ppUnknown);
|
|
|
|
// Initialize
|
|
*ppUnknown = NULL;
|
|
|
|
// Set the mimeole compat mode
|
|
MimeOleSetCompatMode(MIMEOLE_COMPAT_OE5);
|
|
|
|
// Create me
|
|
CActiveUrlRequest *pNew = new CActiveUrlRequest(pUnkOuter);
|
|
if (NULL == pNew)
|
|
return TrapError(E_OUTOFMEMORY);
|
|
|
|
// Return the Innter
|
|
*ppUnknown = pNew->GetInner();
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::CActiveUrlRequest
|
|
// --------------------------------------------------------------------------------
|
|
CActiveUrlRequest::CActiveUrlRequest(IUnknown *pUnkOuter) : CPrivateUnknown(pUnkOuter)
|
|
{
|
|
DllAddRef();
|
|
m_pProtSink = NULL;
|
|
m_pBindInfo = NULL;
|
|
m_pszRootUrl = NULL;
|
|
m_pszBodyUrl = NULL;
|
|
m_pUnkKeepAlive = NULL;
|
|
m_pNext = NULL;
|
|
m_pPrev = NULL;
|
|
m_dwState = 0;
|
|
m_pStream = NULL;
|
|
m_hNeedFile = INVALID_HANDLE_VALUE;
|
|
m_dwBSCF = 0;
|
|
InitializeCriticalSection(&m_cs);
|
|
TraceProtocol("CActiveUrlRequest");
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::~CActiveUrlRequest
|
|
// --------------------------------------------------------------------------------
|
|
CActiveUrlRequest::~CActiveUrlRequest(void)
|
|
{
|
|
// Tracing
|
|
TraceProtocol("~CActiveUrlRequest");
|
|
|
|
// These should have been release in IOInetProtocl::Terminate
|
|
Assert(NULL == m_pProtSink && NULL == m_pBindInfo && NULL == m_pUnkKeepAlive);
|
|
|
|
// Release the protcol object just in case
|
|
SafeRelease(m_pProtSink);
|
|
SafeRelease(m_pBindInfo);
|
|
SafeMemFree(m_pszRootUrl);
|
|
SafeMemFree(m_pszBodyUrl);
|
|
SafeRelease(m_pUnkKeepAlive);
|
|
SafeRelease(m_pStream);
|
|
|
|
// Close file...
|
|
if (INVALID_HANDLE_VALUE != m_hNeedFile)
|
|
CloseHandle(m_hNeedFile);
|
|
|
|
// Kill the CS
|
|
DeleteCriticalSection(&m_cs);
|
|
|
|
// Release the Dll
|
|
DllRelease();
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::PrivateQueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrlRequest::PrivateQueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// check params
|
|
if (ppv == NULL)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Init
|
|
*ppv = NULL;
|
|
|
|
// Find IID
|
|
if (IID_IOInetProtocol == riid)
|
|
*ppv = (IOInetProtocol *)this;
|
|
else if (IID_IOInetProtocolInfo == riid)
|
|
*ppv = (IOInetProtocolInfo *)this;
|
|
else if (IID_IOInetProtocolRoot == riid)
|
|
*ppv = (IOInetProtocolRoot *)this;
|
|
else if (IID_IServiceProvider == riid)
|
|
*ppv = (IServiceProvider *)this;
|
|
else
|
|
{
|
|
hr = TrapError(E_NOINTERFACE);
|
|
goto exit;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::_HrInitializeNeedFile
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrlRequest::_HrInitializeNeedFile(LPMESSAGETREE pTree, HBODY hBody)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szFilePath[MAX_PATH + MAX_PATH];
|
|
ULONG cch;
|
|
LPSTR pszFilePath=NULL;
|
|
LPWSTR pwszFile=NULL;
|
|
|
|
// Invalid Args
|
|
Assert(INVALID_HANDLE_VALUE == m_hNeedFile);
|
|
|
|
// Don't need a file ?
|
|
if (FALSE == ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE))
|
|
goto exit;
|
|
|
|
// Set sizeof szFilePath
|
|
cch = ARRAYSIZE(szFilePath);
|
|
|
|
// If cid:
|
|
if (!m_pszBodyUrl || StrCmpNIA(m_pszBodyUrl, "cid:", 4) == 0 || FAILED(PathCreateFromUrlA(m_pszBodyUrl, szFilePath, &cch, 0)))
|
|
{
|
|
// Create temp file (m_pszFileName could be null)
|
|
CHECKHR(hr = CreateTempFile(NULL, NULL, &pszFilePath, &m_hNeedFile));
|
|
}
|
|
else
|
|
{
|
|
// Create temp file
|
|
CHECKHR(hr = CreateTempFile(szFilePath, NULL, &pszFilePath, &m_hNeedFile));
|
|
}
|
|
|
|
// Convert To Unicode
|
|
CHECKALLOC(pwszFile = PszToUnicode(CP_ACP, pszFilePath));
|
|
|
|
// Enter global Critical Section
|
|
DeleteTempFileOnShutdownEx(pszFilePath, NULL);
|
|
|
|
// Don't Free this
|
|
pszFilePath = NULL;
|
|
|
|
// Report the File...
|
|
SideAssert(SUCCEEDED(m_pProtSink->ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE, pwszFile)));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pwszFile);
|
|
SafeMemFree(pszFilePath);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::OnFullyAvailable
|
|
// --------------------------------------------------------------------------------
|
|
void CActiveUrlRequest::OnFullyAvailable(LPCWSTR pszCntType, IStream *pStream, LPMESSAGETREE pTree, HBODY hBody)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cb;
|
|
|
|
// Invalid Arg
|
|
Assert(pszCntType && pStream);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Validate the state
|
|
Assert(m_pProtSink && pStream && NULL == m_pStream);
|
|
|
|
// Tracing
|
|
TraceProtocol("OnFullyAvailable");
|
|
|
|
// Feed the content-type to trident
|
|
m_pProtSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, pszCntType);
|
|
|
|
// GetNeedFile
|
|
CHECKHR(hr = _HrInitializeNeedFile(pTree, hBody));
|
|
|
|
// Create Stream Lock wrapper
|
|
m_pStream = pStream;
|
|
m_pStream->AddRef();
|
|
|
|
// Rewind that bad boy
|
|
CHECKHR(hr = HrRewindStream(m_pStream));
|
|
|
|
// Were complete
|
|
FLAGSET(m_dwState, REQSTATE_DOWNLOADED);
|
|
|
|
// Initialize bind status callback falgs
|
|
m_dwBSCF = BSCF_DATAFULLYAVAILABLE | BSCF_AVAILABLEDATASIZEUNKNOWN | BSCF_FIRSTDATANOTIFICATION | BSCF_INTERMEDIATEDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
|
|
|
|
// Go into report data loop
|
|
CHECKHR(hr = _HrReportData());
|
|
|
|
// First Report Data
|
|
if (m_pProtSink)
|
|
m_pProtSink->ReportResult(S_OK, 0, NULL);
|
|
|
|
// We have reported the result
|
|
FLAGSET(m_dwState, REQSTATE_RESULTREPORTED);
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr))
|
|
_ReportResult(hr);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::OnStartBinding
|
|
// --------------------------------------------------------------------------------
|
|
void CActiveUrlRequest::OnStartBinding(LPCWSTR pszCntType, IStream *pStream, LPMESSAGETREE pTree, HBODY hBody)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Validate the state
|
|
Assert(m_pProtSink && pStream && NULL == m_pStream);
|
|
|
|
// Tracing
|
|
TraceProtocol("OnBinding(pszCntType, pStream)");
|
|
|
|
// Feed the content-type to trident
|
|
m_pProtSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, pszCntType ? pszCntType : L"application/octet-stream");
|
|
|
|
// GetNeedFile
|
|
CHECKHR(hr = _HrInitializeNeedFile(pTree, hBody));
|
|
|
|
// Create Stream Lock wrapper
|
|
m_pStream = pStream;
|
|
m_pStream->AddRef();
|
|
|
|
// Rewind that bad boy
|
|
CHECKHR(hr = HrRewindStream(m_pStream));
|
|
|
|
// Initialize bind status callback falgs
|
|
m_dwBSCF = BSCF_AVAILABLEDATASIZEUNKNOWN | BSCF_FIRSTDATANOTIFICATION;
|
|
|
|
// Go into report data loop, if not writing to needfile (needfile is processed only when all the data is available)
|
|
if (FALSE == ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE))
|
|
{
|
|
// Report me some data
|
|
CHECKHR(hr = _HrReportData());
|
|
}
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr))
|
|
_ReportResult(hr);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::OnBindingDataAvailable
|
|
// --------------------------------------------------------------------------------
|
|
void CActiveUrlRequest::OnBindingDataAvailable(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Validate the state
|
|
Assert(m_pProtSink && m_pStream);
|
|
|
|
// Tracing
|
|
TraceProtocol("OnBindingDataAvailable");
|
|
|
|
// Initialize bind status callback falgs
|
|
FLAGSET(m_dwBSCF, BSCF_INTERMEDIATEDATANOTIFICATION);
|
|
|
|
// Go into report data loop, if not writing to needfile (needfile is processed only when all the data is available)
|
|
if (FALSE == ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE))
|
|
{
|
|
// Report some data
|
|
CHECKHR(hr = _HrReportData());
|
|
}
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr))
|
|
_ReportResult(hr);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::OnBindingComplete
|
|
// --------------------------------------------------------------------------------
|
|
void CActiveUrlRequest::OnBindingComplete(HRESULT hrResult)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Were complete
|
|
FLAGSET(m_dwState, INETPROT_DOWNLOADED);
|
|
|
|
// Tracing
|
|
TraceProtocol("OnBindingComplete");
|
|
|
|
// No Sink ?
|
|
if (NULL == m_pProtSink)
|
|
return;
|
|
|
|
// Failure
|
|
if (FAILED(hrResult))
|
|
{
|
|
_ReportResult(hrResult);
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize bind status callback falgs
|
|
m_dwBSCF = BSCF_DATAFULLYAVAILABLE | BSCF_AVAILABLEDATASIZEUNKNOWN | BSCF_FIRSTDATANOTIFICATION | BSCF_INTERMEDIATEDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
|
|
|
|
// Report last amount of data
|
|
CHECKHR(hr = _HrReportData());
|
|
|
|
// Tell sink to use the default protocol
|
|
m_pProtSink->ReportResult(S_OK, 0, NULL);
|
|
|
|
// We have reported the result
|
|
FLAGSET(m_dwState, REQSTATE_RESULTREPORTED);
|
|
|
|
exit:
|
|
// Failure
|
|
if (FAILED(hr))
|
|
_ReportResult(hr);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::_ReportResult
|
|
// --------------------------------------------------------------------------------
|
|
void CActiveUrlRequest::_ReportResult(HRESULT hrResult)
|
|
{
|
|
// Locals
|
|
LPWSTR pwszRedirUrl=NULL;
|
|
|
|
// We should have a sink
|
|
Assert(m_pProtSink);
|
|
|
|
// No Sink ?
|
|
if (m_pProtSink && !ISFLAGSET(m_dwState, REQSTATE_RESULTREPORTED))
|
|
{
|
|
// If Failure
|
|
if (FAILED(hrResult))
|
|
{
|
|
// If we have a body Url
|
|
if (m_pszBodyUrl)
|
|
pwszRedirUrl = PszToUnicode(CP_ACP, m_pszBodyUrl);
|
|
|
|
// Report Result,
|
|
if (pwszRedirUrl)
|
|
{
|
|
TraceProtocol("_ReportResult(BINDSTATUS_REDIRECTING)");
|
|
m_pProtSink->ReportResult(INET_E_REDIRECTING, 0, pwszRedirUrl);
|
|
}
|
|
else
|
|
{
|
|
TraceProtocol("_ReportResult(INET_E_USE_DEFAULT_PROTOCOLHANDLER)");
|
|
m_pProtSink->ReportResult(INET_E_USE_DEFAULT_PROTOCOLHANDLER, 0, NULL);
|
|
}
|
|
}
|
|
|
|
// Otherwise, report the result
|
|
else
|
|
{
|
|
TraceProtocol("_ReportResult(INET_E_USE_DEFAULT_PROTOCOLHANDLER)");
|
|
m_pProtSink->ReportResult(S_OK, 0, NULL);
|
|
}
|
|
|
|
// Cleanup
|
|
SafeMemFree(pwszRedirUrl);
|
|
|
|
// We have reported the result
|
|
FLAGSET(m_dwState, REQSTATE_RESULTREPORTED);
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::_HrReportData
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrlRequest::_HrReportData(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// We better have a data source
|
|
Assert(m_pStream);
|
|
|
|
// Tracing
|
|
TraceProtocol("_HrReportData");
|
|
|
|
// BINDF_NEEDFILE
|
|
if (ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE))
|
|
{
|
|
// Dump to File
|
|
CHECKHR(hr = _HrStreamToNeedFile());
|
|
}
|
|
else
|
|
{
|
|
// Report Data
|
|
SideAssert(SUCCEEDED(m_pProtSink->ReportData(m_dwBSCF, 0, 0)));
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::_HrStreamToNeedFile
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrlRequest::_HrStreamToNeedFile(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbTotal=0;
|
|
|
|
// We better have a needfile
|
|
Assert(INVALID_HANDLE_VALUE != m_hNeedFile && ISFLAGSET(m_dwState, REQSTATE_DOWNLOADED));
|
|
|
|
// Write the stream to a file
|
|
hr = WriteStreamToFileHandle(m_pStream, m_hNeedFile, &cbTotal);
|
|
if (FAILED(hr) && E_PENDING != hr)
|
|
{
|
|
TrapError(hr);
|
|
goto exit;
|
|
}
|
|
|
|
// Close the 77file
|
|
CloseHandle(m_hNeedFile);
|
|
m_hNeedFile = INVALID_HANDLE_VALUE;
|
|
|
|
// Rewind the stream incase urlmon trys to read from me as well
|
|
HrRewindStream(m_pStream);
|
|
|
|
// All the data is there
|
|
SideAssert(SUCCEEDED(m_pProtSink->ReportData(m_dwBSCF, 0, 0)));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::Start
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CActiveUrlRequest::Start(LPCWSTR pwszUrl, IOInetProtocolSink *pProtSink,
|
|
IOInetBindInfo *pBindInfo, DWORD grfSTI, HANDLE_PTR dwReserved)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPSTR pszUrl=NULL;
|
|
LPMESSAGETREE pTree=NULL;
|
|
DWORD dwBindF;
|
|
BINDINFO rBindInfo;
|
|
|
|
// Invalid Args
|
|
if (NULL == pwszUrl || NULL == pProtSink || NULL == pBindInfo)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Check State
|
|
Assert(g_pUrlCache && m_pProtSink == NULL && m_pBindInfo == NULL);
|
|
|
|
// BINDF_NEEDFILE
|
|
ZeroMemory(&rBindInfo, sizeof(BINDINFO));
|
|
rBindInfo.cbSize = sizeof(BINDINFO);
|
|
if (SUCCEEDED(pBindInfo->GetBindInfo(&dwBindF, &rBindInfo)) && ISFLAGSET(dwBindF, BINDF_NEEDFILE))
|
|
{
|
|
// Set Flag
|
|
FLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE);
|
|
}
|
|
|
|
// Assume the Sink
|
|
m_pProtSink = pProtSink;
|
|
m_pProtSink->AddRef();
|
|
|
|
// Assume the BindInfo
|
|
m_pBindInfo = pBindInfo;
|
|
m_pBindInfo->AddRef();
|
|
|
|
// Dup the Url
|
|
CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwszUrl));
|
|
|
|
// Unescape inplace
|
|
CHECKHR(hr = UrlUnescapeA(pszUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
|
|
|
|
// Split the Url
|
|
CHECKHR(hr = MimeOleParseMhtmlUrl(pszUrl, &m_pszRootUrl, &m_pszBodyUrl));
|
|
|
|
// for security purposes, disallow navigate using the mhtml protocl in IE except with correct ext
|
|
// wait to do this check until after we have a protocol sink to report the error and we've parsed
|
|
// out the root url
|
|
if (StrCmpNI(m_pszRootUrl, TEXT("mid:"), 4) && GetModuleHandle(TEXT("IEXPLORE.EXE")))
|
|
{
|
|
LPTSTR pszExt = PathFindExtension(m_pszRootUrl);
|
|
if (!pszExt || (StrCmpI(pszExt, TEXT(".mht")) && StrCmpI(pszExt, TEXT(".mhtml"))))
|
|
{
|
|
hr = INET_E_SECURITY_PROBLEM;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Tracing
|
|
TraceProtocol("Start");
|
|
|
|
// Try to resolve the root url
|
|
CHECKHR(hr = g_pUrlCache->ActiveObjectFromUrl(m_pszRootUrl, TRUE, IID_CMessageTree, (LPVOID *)&pTree, &m_pUnkKeepAlive));
|
|
|
|
// Ask the BindTree to Resolve this Url
|
|
CHECKHR(hr = pTree->HrActiveUrlRequest(this));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszUrl);
|
|
SafeRelease(pTree);
|
|
|
|
// Failure
|
|
//if (FAILED(hr))
|
|
// _ReportResult(E_FAIL);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::Terminate
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CActiveUrlRequest::Terminate(DWORD dwOptions)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Tracing
|
|
TraceProtocol("Terminate");
|
|
|
|
// Release Objects
|
|
SafeRelease(m_pProtSink);
|
|
SafeRelease(m_pBindInfo);
|
|
SafeRelease(m_pUnkKeepAlive);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::Read (IOInetProtocol)
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CActiveUrlRequest::Read(LPVOID pv,ULONG cb, ULONG *pcbRead)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbRead;
|
|
|
|
// Init
|
|
if (pcbRead)
|
|
*pcbRead = 0;
|
|
|
|
// No Stream Yet
|
|
if (NULL == m_pStream)
|
|
{
|
|
Assert(FALSE);
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Read from the external offset
|
|
CHECKHR(hr = m_pStream->Read(pv, cb, &cbRead));
|
|
|
|
// Done
|
|
if (0 == cbRead)
|
|
{
|
|
// S_FALSE = Were Done, E_PENDING = more data is coming
|
|
hr = (ISFLAGSET(m_dwState, INETPROT_DOWNLOADED)) ? S_FALSE : E_PENDING;
|
|
}
|
|
|
|
// Otherwise, set to ok
|
|
else
|
|
hr = S_OK;
|
|
|
|
// Return pcbRead
|
|
if (pcbRead)
|
|
*pcbRead = cbRead;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::Seek (IOInetProtocol)
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CActiveUrlRequest::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNew)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Tracing
|
|
TraceProtocol("Seek");
|
|
|
|
// No Stream Yet
|
|
if (NULL == m_pStream)
|
|
{
|
|
Assert(FALSE);
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Call Utility Function
|
|
CHECKHR(hr = m_pStream->Seek(dlibMove, dwOrigin, plibNew));
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::QueryService
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CActiveUrlRequest::QueryService(REFGUID rsid, REFIID riid, void **ppvObject) /* IServiceProvider */
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
IServiceProvider *pSP=NULL;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Tracing
|
|
TraceProtocol("QueryService");
|
|
|
|
// No Protocol Sink Yet ?
|
|
if (NULL == m_pProtSink)
|
|
{
|
|
hr = TrapError(E_UNEXPECTED);
|
|
goto exit;
|
|
}
|
|
|
|
// QI the Sink for the IServiceProvider
|
|
CHECKHR(hr = m_pProtSink->QueryInterface(IID_IServiceProvider, (LPVOID *)&pSP));
|
|
|
|
// Query Service the Service Provider
|
|
CHECKHR(hr = pSP->QueryService(rsid, riid, ppvObject));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pSP);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::_FillReturnString
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrlRequest::_FillReturnString(LPCWSTR pszUrl, DWORD cchUrl, LPWSTR pszResult,
|
|
DWORD cchResult, DWORD *pcchResult)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Want the Size
|
|
if (pcchResult)
|
|
*pcchResult = cchUrl;
|
|
|
|
// No return value
|
|
if (NULL == pszResult)
|
|
goto exit;
|
|
|
|
// Dest is big enought
|
|
if (cchResult < cchUrl+1)
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Copy to dest buffer
|
|
CopyMemory((LPBYTE)pszResult, (LPBYTE)pszUrl, ((cchUrl + 1) * sizeof(WCHAR)));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::ParseUrl
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CActiveUrlRequest::ParseUrl(LPCWSTR pwzUrl, PARSEACTION ParseAction,
|
|
DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cchUrl;
|
|
LPSTR pszUrl=NULL;
|
|
LPSTR pszRootUrl=NULL;
|
|
LPSTR pszBodyUrl=NULL;
|
|
LPWSTR pwszBodyUrl=NULL;
|
|
LPWSTR pszRootUrlW=NULL;
|
|
LPWSTR pszSecurityUrlW=NULL;
|
|
PROPVARIANT rVariant;
|
|
|
|
// Invalid Arg
|
|
if (NULL == pwzUrl)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Tracing
|
|
DOUTL(APP_DOUTL, "%08X > 0x%08X CActiveUrlRequest::ParseUrl (pwzUrl = %ls)", GetCurrentThreadId(), this, pwzUrl);
|
|
|
|
// Setup Variant
|
|
ZeroMemory(&rVariant, sizeof(PROPVARIANT));
|
|
|
|
// Only handle PARSE_CANONICALIZE
|
|
if (PARSE_CANONICALIZE == ParseAction)
|
|
{
|
|
// Fill return value
|
|
CHECKHR(hr = _FillReturnString(pwzUrl, lstrlenW(pwzUrl), pwzResult, cchResult, pcchResult));
|
|
}
|
|
|
|
// Strip MHTML: and return
|
|
#ifndef WIN16
|
|
else if (StrCmpNIW(pwzUrl, L"mhtml:", 6) == 0)
|
|
#else
|
|
else if (StrCmpNIW(pwzUrl, "mhtml:", 6) == 0)
|
|
#endif // !WIN16
|
|
{
|
|
// If Getting Friendly
|
|
if (PARSE_FRIENDLY == ParseAction)
|
|
{
|
|
// To ANSI
|
|
CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwzUrl));
|
|
|
|
// Split It
|
|
CHECKHR(hr = MimeOleParseMhtmlUrl(pszUrl, &pszRootUrl, &pszBodyUrl));
|
|
|
|
// Convert To Unicode
|
|
CHECKALLOC(pwszBodyUrl = PszToUnicode(CP_ACP, pszBodyUrl));
|
|
|
|
// Fill return value
|
|
CHECKHR(hr = _FillReturnString(pwszBodyUrl, lstrlenW(pwszBodyUrl), pwzResult, cchResult, pcchResult));
|
|
}
|
|
|
|
// If the content-location is available, use it as the security URL
|
|
else if (PARSE_SECURITY_URL == ParseAction)
|
|
{
|
|
BOOL fGotSecURL = FALSE;
|
|
LPMESSAGETREE pTree=NULL;
|
|
HBODY hBody;
|
|
IInternetSecurityManager *pISM;
|
|
DWORD dwZone=URLZONE_UNTRUSTED;
|
|
|
|
// Base to ANSI
|
|
CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwzUrl));
|
|
|
|
// UnEscape the Url
|
|
CHECKHR(hr = UrlUnescapeA(pszUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
|
|
|
|
// Split It
|
|
CHECKHR(hr = MimeOleParseMhtmlUrl(pszUrl, &pszRootUrl, &pszBodyUrl));
|
|
|
|
// RootUrl to UNICODE
|
|
CHECKALLOC(pszRootUrlW = PszToUnicode(CP_ACP, pszRootUrl));
|
|
|
|
// Check and see what ZONE the root url is running in
|
|
if (CoInternetCreateSecurityManager(NULL, &pISM, 0)==S_OK)
|
|
{
|
|
pISM->MapUrlToZone(pszRootUrlW, &dwZone, 0);
|
|
pISM->Release();
|
|
}
|
|
|
|
// default to the root-body part
|
|
pszSecurityUrlW = pszRootUrlW;
|
|
|
|
// if the root url is in the local-machine, then respect the Content-Location header
|
|
// as the source of the url, otherwise defer to the root url
|
|
if ((dwZone == URLZONE_LOCAL_MACHINE) &&
|
|
SUCCEEDED(g_pUrlCache->ActiveObjectFromUrl(pszRootUrl, FALSE, IID_CMessageTree, (LPVOID *)&pTree, NULL)))
|
|
{
|
|
if ( (pszBodyUrl != NULL && SUCCEEDED(pTree->ResolveURL(NULL, NULL, pszBodyUrl, 0, &hBody))) ||
|
|
SUCCEEDED(pTree->GetTextBody(TXT_HTML, IET_BINARY, NULL, &hBody)))
|
|
{
|
|
// Locals
|
|
LPWSTR pwszSecURL = NULL;
|
|
PSUACTION psua = (dwParseFlags == PSU_SECURITY_URL_ONLY)? PSU_SECURITY_URL_ONLY: PSU_DEFAULT;
|
|
|
|
rVariant.vt = VT_LPWSTR;
|
|
|
|
if (SUCCEEDED(pTree->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTLOC), NOFLAGS, &rVariant)) && rVariant.pwszVal && *rVariant.pwszVal)
|
|
{
|
|
pszSecurityUrlW = rVariant.pwszVal;
|
|
}
|
|
SafeMemFree(pwszSecURL);
|
|
}
|
|
}
|
|
|
|
// Fill return value
|
|
CHECKHR(hr = _FillReturnString(pszSecurityUrlW, lstrlenW(pszSecurityUrlW), pwzResult, cchResult, pcchResult));
|
|
|
|
SafeRelease(pTree);
|
|
}
|
|
|
|
else if (PARSE_ENCODE == ParseAction)
|
|
{
|
|
hr = INET_E_DEFAULT_ACTION;
|
|
}
|
|
|
|
// Simply remove mhtml:
|
|
else
|
|
{
|
|
// Fill return value
|
|
CHECKHR(hr = _FillReturnString(pwzUrl + 6, lstrlenW(pwzUrl) - 6, pwzResult, cchResult, pcchResult));
|
|
}
|
|
}
|
|
|
|
// INET_E_DEFAULT_ACTION
|
|
else
|
|
{
|
|
hr = INET_E_DEFAULT_ACTION;
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszUrl);
|
|
SafeMemFree(pszRootUrl);
|
|
SafeMemFree(pszRootUrlW);
|
|
SafeMemFree(pszBodyUrl);
|
|
SafeMemFree(pwszBodyUrl);
|
|
SafeMemFree(rVariant.pwszVal);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::QueryInfo
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CActiveUrlRequest::QueryInfo(LPCWSTR pwzUrl, QUERYOPTION OueryOption,
|
|
DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD *pcbBuf, DWORD dwReserved)
|
|
{
|
|
// QUERY_RECOMBINE
|
|
if (QUERY_RECOMBINE == OueryOption)
|
|
{
|
|
// Sure
|
|
if (cbBuffer < sizeof(DWORD))
|
|
return S_FALSE;
|
|
|
|
// True
|
|
DWORD dw=TRUE;
|
|
CopyMemory(pBuffer, &dw, sizeof(dw));
|
|
*pcbBuf = sizeof(dw);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// Failure
|
|
return INET_E_QUERYOPTION_UNKNOWN;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrlRequest::CombineUrl
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CActiveUrlRequest::CombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags,
|
|
LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPSTR pszBaseUrl=NULL;
|
|
LPSTR pszRootUrl=NULL;
|
|
LPSTR pszBodyUrl=NULL;
|
|
LPSTR pszRelativeUrl=NULL;
|
|
LPSTR pszNewUrl=NULL;
|
|
LPSTR pszDocUrl=NULL;
|
|
LPSTR pszPageUrl=NULL;
|
|
LPWSTR pwszBodyUrl=NULL;
|
|
LPWSTR pwszNewUrl=NULL;
|
|
LPWSTR pwszSource=NULL;
|
|
BOOL fCombine=FALSE;
|
|
LPMESSAGETREE pTree=NULL;
|
|
ULONG cchSource;
|
|
ULONG cchPrefix=lstrlen(c_szMHTMLColon);
|
|
HBODY hBody;
|
|
|
|
// Invalid Arg
|
|
if (NULL == pwzRelativeUrl)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// DebugTraceing
|
|
#ifndef WIN16
|
|
DOUTL(APP_DOUTL, "%08X > 0x%08X CActiveUrlRequest::CombineUrl - Base = %ls, Relative = %ls", GetCurrentThreadId(), this, pwzBaseUrl ? pwzBaseUrl : L"" , pwzRelativeUrl ? pwzRelativeUrl : L"");
|
|
#else
|
|
DOUTL(APP_DOUTL, "%08X > 0x%08X CActiveUrlRequest::CombineUrl - Base = %ls, Relative = %ls", GetCurrentThreadId(), this, pwzBaseUrl ? pwzBaseUrl : "" , pwzRelativeUrl ? pwzRelativeUrl : "");
|
|
#endif // !WIN16
|
|
|
|
// Raid-42722: MHTML: Bookmarks don't work
|
|
if (L'#' == pwzRelativeUrl[0])
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
// Convert relative to ANSI
|
|
CHECKALLOC(pszRelativeUrl = PszToANSI(CP_ACP, pwzRelativeUrl));
|
|
|
|
// We should UnEscape only Url, but doesn't touch a query
|
|
CHECKHR(hr = UrlUnescapeA(pszRelativeUrl, NULL, NULL, URL_UNESCAPE_INPLACE | URL_DONT_ESCAPE_EXTRA_INFO));
|
|
|
|
// If the relative is already mhtml:, then retur that...
|
|
if (StrCmpNI(pszRelativeUrl, c_szMHTMLColon, cchPrefix) == 0)
|
|
{
|
|
// Split It
|
|
CHECKHR(hr = MimeOleParseMhtmlUrl(pszRelativeUrl, &pszRootUrl, &pszBodyUrl));
|
|
|
|
// If no body url, then just return pszRelativeUrl
|
|
if (NULL == pszBodyUrl)
|
|
{
|
|
// Set pwszSource
|
|
pwszSource = (LPWSTR)(pwzRelativeUrl + cchPrefix);
|
|
|
|
// Get Length
|
|
cchSource = lstrlenW(pwzRelativeUrl) - cchPrefix;
|
|
|
|
// Done
|
|
goto set_return;
|
|
}
|
|
}
|
|
|
|
// Otherwise, build a new url
|
|
else
|
|
{
|
|
// Base to ANSI
|
|
CHECKALLOC(pszBaseUrl = PszToANSI(CP_ACP, pwzBaseUrl));
|
|
|
|
// UnEscape the Url
|
|
CHECKHR(hr = UrlUnescapeA(pszBaseUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
|
|
|
|
// Split It
|
|
CHECKHR(hr = MimeOleParseMhtmlUrl(pszBaseUrl, &pszRootUrl, &pszPageUrl));
|
|
|
|
// Set pszBodyUrl
|
|
pszBodyUrl = pszRelativeUrl;
|
|
|
|
// Don't need pszRelativeUrl anymore
|
|
pszRelativeUrl = NULL;
|
|
}
|
|
|
|
// Better have a root and a body url
|
|
Assert(pszRootUrl && pszBodyUrl);
|
|
|
|
// Try to resolve the root url
|
|
if (SUCCEEDED(g_pUrlCache->ActiveObjectFromUrl(pszRootUrl, FALSE, IID_CMessageTree, (LPVOID *)&pTree, NULL)))
|
|
{
|
|
// If pszBodyUrl is in the WebBook or the bind is not finished...then do the url combine
|
|
if (SUCCEEDED(pTree->ResolveURL(NULL, NULL, pszBodyUrl, 0, NULL)) || pTree->IsState(TREESTATE_BINDDONE) == S_FALSE)
|
|
{
|
|
// Combine the Urls
|
|
fCombine = TRUE;
|
|
}
|
|
// fCombine = TRUE;
|
|
}
|
|
|
|
// Should we combine
|
|
if (fCombine)
|
|
{
|
|
// Allocate Some Memory
|
|
DWORD cchSize = (cchPrefix + lstrlen(pszRootUrl) + lstrlen(pszBodyUrl) + 2);
|
|
CHECKALLOC(pszNewUrl = PszAllocA(cchSize));
|
|
|
|
// Format the string
|
|
wnsprintfA(pszNewUrl, cchSize, "%s%s!%s", c_szMHTMLColon, pszRootUrl, pszBodyUrl);
|
|
|
|
// Convert to unicode
|
|
CHECKALLOC(pwszNewUrl = PszToUnicode(CP_ACP, pszNewUrl));
|
|
|
|
// Get length
|
|
cchSource = lstrlenW(pwszNewUrl);
|
|
|
|
// Set Source
|
|
pwszSource = pwszNewUrl;
|
|
}
|
|
|
|
// No Combine
|
|
else
|
|
{
|
|
// If we have a WebBook
|
|
if (pTree)
|
|
{
|
|
// If we don't have a page Url, then just call GetTextBody(html)
|
|
if (NULL == pszPageUrl)
|
|
MimeOleComputeContentBase(pTree, NULL, &pszDocUrl, NULL);
|
|
|
|
// Otherwise, try to resolve the page url
|
|
else if (SUCCEEDED(pTree->ResolveURL(NULL, NULL, pszPageUrl, 0, &hBody)))
|
|
pszDocUrl = MimeOleContentBaseFromBody(pTree, hBody);
|
|
|
|
// If we have Url
|
|
if (pszDocUrl)
|
|
{
|
|
// Unescape It
|
|
CHECKHR(hr = UrlUnescapeA(pszDocUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
|
|
}
|
|
|
|
// Otheriwse, if the WebBook was loaded by a moniker, then use pszRootUrl
|
|
else if (pTree->IsState(TREESTATE_LOADEDBYMONIKER) == S_OK)
|
|
{
|
|
// pszRootUrl is the pszDocUrl
|
|
CHECKALLOC(pszDocUrl = PszDupA(pszRootUrl));
|
|
}
|
|
}
|
|
|
|
// If there is a pszDocUrl
|
|
if (pszDocUrl)
|
|
{
|
|
// Lets Combine with this url
|
|
CHECKHR(hr = MimeOleCombineURL(pszDocUrl, lstrlen(pszDocUrl), pszBodyUrl, lstrlen(pszBodyUrl), FALSE, &pszNewUrl));
|
|
|
|
// Convert to unicode
|
|
CHECKALLOC(pwszNewUrl = PszToUnicode(CP_ACP, pszNewUrl));
|
|
|
|
// Get length
|
|
cchSource = lstrlenW(pwszNewUrl);
|
|
|
|
// Set Source
|
|
pwszSource = pwszNewUrl;
|
|
}
|
|
else
|
|
{
|
|
// Need a wide body Url
|
|
CHECKALLOC(pwszBodyUrl = PszToUnicode(CP_ACP, pszBodyUrl));
|
|
|
|
// Get length
|
|
cchSource = lstrlenW(pwszBodyUrl);
|
|
|
|
// Set Source
|
|
pwszSource = pwszBodyUrl;
|
|
}
|
|
}
|
|
|
|
set_return:
|
|
// Set Dest Size
|
|
if (pcchResult)
|
|
*pcchResult = cchSource;
|
|
|
|
// No return value
|
|
if (NULL == pwzResult)
|
|
goto exit;
|
|
|
|
// Dest is big enought
|
|
if (cchResult <= cchSource)
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Copy to dest buffer
|
|
CopyMemory((LPBYTE)pwzResult, (LPBYTE)pwszSource, ((cchSource + 1) * sizeof(WCHAR)));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pszRootUrl);
|
|
SafeMemFree(pszRelativeUrl);
|
|
SafeMemFree(pszBodyUrl);
|
|
SafeMemFree(pszNewUrl);
|
|
SafeMemFree(pwszNewUrl);
|
|
SafeMemFree(pszBaseUrl);
|
|
SafeMemFree(pszDocUrl);
|
|
SafeMemFree(pwszBodyUrl);
|
|
SafeMemFree(pszPageUrl);
|
|
SafeRelease(pTree);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::CActiveUrl
|
|
// --------------------------------------------------------------------------------
|
|
CActiveUrl::CActiveUrl(void)
|
|
{
|
|
m_cRef = 1;
|
|
m_pUnkAlive = NULL;
|
|
m_pUnkInner = NULL;
|
|
m_pWebBook = NULL;
|
|
m_pNext = NULL;
|
|
m_pPrev = NULL;
|
|
m_dwFlags = 0;
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::~CActiveUrl
|
|
// --------------------------------------------------------------------------------
|
|
CActiveUrl::~CActiveUrl(void)
|
|
{
|
|
SafeRelease(m_pUnkAlive);
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::QueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CActiveUrl::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// check params
|
|
if (ppv == NULL)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Find IID
|
|
if (IID_IUnknown == riid)
|
|
*ppv = (IUnknown *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = TrapError(E_NOINTERFACE);
|
|
goto exit;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::AddRef
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CActiveUrl::AddRef(void)
|
|
{
|
|
return (ULONG)InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::Release
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CActiveUrl::Release(void)
|
|
{
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::Init
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrl::Init(BINDF bindf, LPMESSAGETREE pTree)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Better not have data
|
|
Assert(NULL == m_pWebBook && NULL == m_pUnkInner);
|
|
|
|
// No Message Object Passed in ?
|
|
if (NULL == pTree)
|
|
{
|
|
// Allocate the Message Object
|
|
CHECKALLOC(pTree = new CMessageTree);
|
|
|
|
// Set pMessage
|
|
m_pUnkAlive = pTree->GetInner();
|
|
|
|
// Init
|
|
CHECKHR(hr = pTree->InitNew());
|
|
}
|
|
|
|
// Set BINDF_PRAGMA_NO_CACHE
|
|
if (ISFLAGSET(bindf, BINDF_RESYNCHRONIZE))
|
|
{
|
|
// Set State
|
|
pTree->SetState(TREESTATE_RESYNCHRONIZE);
|
|
}
|
|
|
|
// Set pMessage
|
|
m_pWebBook = pTree;
|
|
|
|
// Get the Message Object's Inner Unknown
|
|
m_pUnkInner = pTree->GetInner();
|
|
|
|
// Register pActiveUrl as a handle in the message object
|
|
m_pWebBook->SetActiveUrl(this);
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::DontKeepAlive
|
|
// --------------------------------------------------------------------------------
|
|
void CActiveUrl::DontKeepAlive(void)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Set pMessage
|
|
if (m_pUnkAlive)
|
|
{
|
|
// Somebody should still have a refcount on this dude
|
|
SideAssert(m_pUnkAlive->Release() > 0);
|
|
|
|
// Null It
|
|
m_pUnkAlive = NULL;
|
|
}
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::IsActive
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrl::IsActive(void)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
HRESULT hr = m_pWebBook ? S_OK : S_FALSE;
|
|
LeaveCriticalSection(&m_cs);
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::RevokeWebBook
|
|
// --------------------------------------------------------------------------------
|
|
void CActiveUrl::RevokeWebBook(LPMESSAGETREE pTree)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Invalid Arg
|
|
Assert(NULL == pTree || m_pWebBook == pTree);
|
|
|
|
// Revoke This from the message
|
|
if (m_pWebBook)
|
|
m_pWebBook->SetActiveUrl(NULL);
|
|
|
|
// Null m_pWebBook
|
|
m_pWebBook = NULL;
|
|
m_pUnkInner = NULL;
|
|
|
|
// Check Ref Count
|
|
Assert(1 == m_cRef);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::CompareRootUrl
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrl::CompareRootUrl(LPCSTR pszUrl)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Compare Root Url
|
|
HRESULT hr = m_pWebBook ? m_pWebBook->CompareRootUrl(pszUrl) : S_FALSE;
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::BindToObject
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrl::BindToObject(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Compare Root Url
|
|
HRESULT hr = m_pUnkInner ? m_pUnkInner->QueryInterface(riid, ppv) : TrapError(E_FAIL);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CActiveUrl::CreateWebPage
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CActiveUrl::CreateWebPage(IStream *pStmRoot, LPWEBPAGEOPTIONS pOptions,
|
|
DWORD dwReserved, IMoniker **ppMoniker)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// No Message
|
|
if (NULL == m_pWebBook)
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// CreateWebPage
|
|
CHECKHR(hr = m_pWebBook->CreateWebPage(pStmRoot, pOptions, NULL, ppMoniker));
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::CMimeActiveUrlCache
|
|
// --------------------------------------------------------------------------------
|
|
CMimeActiveUrlCache::CMimeActiveUrlCache(void)
|
|
{
|
|
m_cRef = 1;
|
|
m_cActive = 0;
|
|
m_pHead = NULL;
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::~CMimeActiveUrlCache
|
|
// --------------------------------------------------------------------------------
|
|
CMimeActiveUrlCache::~CMimeActiveUrlCache(void)
|
|
{
|
|
_FreeActiveUrlList(TRUE);
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::_FreeActiveUrlList
|
|
// --------------------------------------------------------------------------------
|
|
void CMimeActiveUrlCache::_FreeActiveUrlList(BOOL fAll)
|
|
{
|
|
// Locals
|
|
LPACTIVEURL pCurr;
|
|
LPACTIVEURL pNext;
|
|
|
|
// Init
|
|
pCurr = m_pHead;
|
|
|
|
// All
|
|
if (fAll)
|
|
{
|
|
// Loop and Free
|
|
while(pCurr)
|
|
{
|
|
// Set Next
|
|
pNext = pCurr->PGetNext();
|
|
|
|
// Revoke the handle
|
|
pCurr->RevokeWebBook(NULL);
|
|
|
|
// Free the Active Url
|
|
pCurr->Release();
|
|
|
|
// Goto Next
|
|
pCurr = pNext;
|
|
}
|
|
|
|
// No Active
|
|
m_cActive = 0;
|
|
m_pHead = NULL;
|
|
}
|
|
|
|
else
|
|
{
|
|
// Loop and Free
|
|
while(pCurr)
|
|
{
|
|
// Set Next
|
|
pNext = pCurr->PGetNext();
|
|
|
|
// Revoke the handle
|
|
if (pCurr->IsActive() == S_FALSE)
|
|
_RemoveUrl(pCurr);
|
|
|
|
// Goto Next
|
|
pCurr = pNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::QueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CMimeActiveUrlCache::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// check params
|
|
if (ppv == NULL)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Find IID
|
|
if (IID_IUnknown == riid)
|
|
*ppv = (IUnknown *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = TrapError(E_NOINTERFACE);
|
|
goto exit;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::AddRef
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CMimeActiveUrlCache::AddRef(void)
|
|
{
|
|
return (ULONG)InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::Release
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CMimeActiveUrlCache::Release(void)
|
|
{
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::_RegisterUrl
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimeActiveUrlCache::_RegisterUrl(LPMESSAGETREE pTree, BINDF bindf,
|
|
LPACTIVEURL *ppActiveUrl)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPACTIVEURL pActiveUrl=NULL;
|
|
|
|
// Invalid Arg
|
|
Assert(ppActiveUrl);
|
|
|
|
// Init
|
|
*ppActiveUrl = NULL;
|
|
|
|
// Allocate an ActiveUrl
|
|
CHECKALLOC(pActiveUrl = new CActiveUrl);
|
|
|
|
// Init the Active Url
|
|
CHECKHR(hr = pActiveUrl->Init(bindf, pTree));
|
|
|
|
// Link Into Chain
|
|
if (NULL == m_pHead)
|
|
m_pHead = pActiveUrl;
|
|
else
|
|
{
|
|
pActiveUrl->SetNext(m_pHead);
|
|
m_pHead->SetPrev(pActiveUrl);
|
|
m_pHead = pActiveUrl;
|
|
}
|
|
|
|
// Increment Count
|
|
m_cActive++;
|
|
|
|
// Return It
|
|
*ppActiveUrl = pActiveUrl;
|
|
pActiveUrl = NULL;
|
|
|
|
exit:
|
|
// Release the Active Url
|
|
SafeRelease(pActiveUrl);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::_ResolveUrl
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimeActiveUrlCache::_ResolveUrl(LPCSTR pszUrl, LPACTIVEURL *ppActiveUrl)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPACTIVEURL pActiveUrl;
|
|
|
|
// Invalid Arg
|
|
Assert(pszUrl && ppActiveUrl);
|
|
|
|
// Init
|
|
*ppActiveUrl = NULL;
|
|
|
|
// Should not have mhtml:
|
|
Assert(StrCmpNI(pszUrl, "mhtml:", 6) != 0);
|
|
|
|
// Walk the Table
|
|
for (pActiveUrl=m_pHead; pActiveUrl!=NULL; pActiveUrl=pActiveUrl->PGetNext())
|
|
{
|
|
// Is this the Url
|
|
if (pActiveUrl->CompareRootUrl(pszUrl) == S_OK)
|
|
{
|
|
// Return the Active Url
|
|
*ppActiveUrl = pActiveUrl;
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Not Found
|
|
hr = TrapError(MIME_E_NOT_FOUND);
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::_RemoveUrl
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimeActiveUrlCache::_RemoveUrl(LPACTIVEURL pActiveUrl)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Fixup Linked List
|
|
LPACTIVEURL pNext = pActiveUrl->PGetNext();
|
|
LPACTIVEURL pPrev = pActiveUrl->PGetPrev();
|
|
|
|
// Fixup
|
|
if (pPrev)
|
|
pPrev->SetNext(pNext);
|
|
if (pNext)
|
|
pNext->SetPrev(pPrev);
|
|
|
|
// Fixup m_pHead
|
|
if (m_pHead == pActiveUrl)
|
|
m_pHead = pNext;
|
|
|
|
// Revoke the handle
|
|
pActiveUrl->RevokeWebBook(NULL);
|
|
|
|
// Release the ActiveUrl
|
|
SideAssert(0 == pActiveUrl->Release());
|
|
|
|
// One less active
|
|
m_cActive--;
|
|
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return S_OK;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::RemoveUrl
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimeActiveUrlCache::RemoveUrl(LPACTIVEURL pActiveUrl)
|
|
{
|
|
return _RemoveUrl(pActiveUrl);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::_HandlePragmaNoCache
|
|
// --------------------------------------------------------------------------------
|
|
void CMimeActiveUrlCache::_HandlePragmaNoCache(BINDF bindf, LPCSTR pszUrl)
|
|
{
|
|
// Locals
|
|
CActiveUrl *pActiveUrl;
|
|
|
|
// Invalid Arg
|
|
Assert(pszUrl);
|
|
|
|
// BINDF_PRAGMA_NO_CACHE - Reload the WebBook from original source (can't do if activeurl has a fake url)
|
|
if (ISFLAGSET((DWORD)bindf, BINDF_PRAGMA_NO_CACHE))
|
|
{
|
|
// Try to find the ActiveUrl associated with pszUrl
|
|
if (SUCCEEDED(_ResolveUrl(pszUrl, &pActiveUrl)))
|
|
{
|
|
// If it is a fakeurl, then lets not unload it
|
|
if (FALSE == pActiveUrl->FIsFlagSet(ACTIVEURL_ISFAKEURL))
|
|
{
|
|
// Kill it from the cache so that its not found and reloaded
|
|
_RemoveUrl(pActiveUrl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::ActiveObjectFromMoniker - Called from Trident
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimeActiveUrlCache::ActiveObjectFromMoniker(
|
|
/* in */ BINDF bindf,
|
|
/* in */ IMoniker *pmkOriginal,
|
|
/* in */ IBindCtx *pBindCtx,
|
|
/* in */ REFIID riid,
|
|
/* out */ LPVOID *ppvObject,
|
|
/* out */ IMoniker **ppmkNew)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPWSTR pwszUrl=NULL;
|
|
LPSTR pszUrl=NULL;
|
|
LPSTR pszRootUrl=NULL;
|
|
IMoniker *pMoniker=NULL;
|
|
IPersistMoniker *pPersist=NULL;
|
|
LPACTIVEURL pActiveUrl=NULL;
|
|
BOOL fAsync=FALSE;
|
|
WEBPAGEOPTIONS Options={0};
|
|
|
|
// Invalid Arg
|
|
if (NULL == pmkOriginal || NULL == ppvObject || NULL == ppmkNew)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Init
|
|
*ppmkNew = NULL;
|
|
*ppvObject = NULL;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Get the Url from the Moniker
|
|
CHECKHR(hr = pmkOriginal->GetDisplayName(NULL, NULL, &pwszUrl));
|
|
|
|
// Convert to ANSI
|
|
CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwszUrl));
|
|
|
|
// Unescape inplace
|
|
CHECKHR(hr = UrlUnescapeA(pszUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
|
|
|
|
// Raid-2508: Comment tag ( <! comment> ) doesn't work in mhtml
|
|
if (StrCmpNI(pszUrl, c_szMHTMLColon, lstrlen(c_szMHTMLColon)) != 0)
|
|
{
|
|
// Fixup
|
|
ReplaceChars(pszUrl, '!', '_');
|
|
}
|
|
|
|
// Free pwszUrl
|
|
SafeMemFree(pwszUrl);
|
|
|
|
// This will fail if pszUrl is not an mhtml: url, if it succeeds it gives me the part Url
|
|
if (SUCCEEDED(MimeOleParseMhtmlUrl(pszUrl, &pszRootUrl, NULL)))
|
|
{
|
|
// _HandlePragmaNoCache
|
|
_HandlePragmaNoCache(bindf, pszRootUrl);
|
|
|
|
// See if pszUrl - mhtml: is an active Url
|
|
if (FAILED(_ResolveUrl(pszRootUrl, &pActiveUrl)))
|
|
{
|
|
// Register an ActiveUrl
|
|
CHECKHR(hr = _RegisterUrl(NULL, bindf, &pActiveUrl));
|
|
|
|
// Convert pszRootUrl to a wide
|
|
CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszRootUrl));
|
|
|
|
// Create an Actual Url Moniker
|
|
CHECKHR(hr = CreateURLMoniker(NULL, pwszUrl, &pMoniker));
|
|
|
|
// Get an IPersistMoniker
|
|
CHECKHR(hr = pActiveUrl->BindToObject(IID_IPersistMoniker, (LPVOID *)&pPersist));
|
|
|
|
// Load the message with pmkOriginal
|
|
hr = pPersist->Load(FALSE, pMoniker, NULL, 0);
|
|
if (FAILED(hr) && E_PENDING != hr && MK_S_ASYNCHRONOUS != hr)
|
|
{
|
|
hr = TrapError(hr);
|
|
goto exit;
|
|
}
|
|
|
|
// Otheriwse, good
|
|
hr = S_OK;
|
|
}
|
|
|
|
// Return pmkOriginal
|
|
(*ppmkNew) = pmkOriginal;
|
|
(*ppmkNew)->AddRef();
|
|
|
|
// QI for the requested object iid
|
|
CHECKHR(hr = pActiveUrl->BindToObject(riid, ppvObject));
|
|
}
|
|
|
|
// Otherwise Simply see if this Url is Active
|
|
else
|
|
{
|
|
// _HandlePragmaNoCache
|
|
_HandlePragmaNoCache(bindf, pszUrl);
|
|
|
|
// Try to resolve this url
|
|
if (FAILED(_ResolveUrl(pszUrl, &pActiveUrl)))
|
|
{
|
|
// Register an ActiveUrl
|
|
CHECKHR(hr = _RegisterUrl(NULL, bindf, &pActiveUrl));
|
|
|
|
// Get an IPersistMoniker
|
|
CHECKHR(hr = pActiveUrl->BindToObject(IID_IPersistMoniker, (LPVOID *)&pPersist));
|
|
|
|
// Load the message with pmkOriginal
|
|
hr = pPersist->Load(FALSE, pmkOriginal, pBindCtx, 0);
|
|
if (FAILED(hr) && E_PENDING != hr && MK_S_ASYNCHRONOUS != hr)
|
|
{
|
|
hr = TrapError(hr);
|
|
goto exit;
|
|
}
|
|
|
|
// Otheriwse, good
|
|
hr = S_OK;
|
|
}
|
|
|
|
// Setup WebPage Options
|
|
Options.cbSize = sizeof(WEBPAGEOPTIONS);
|
|
Options.dwFlags = WPF_NOMETACHARSET | WPF_HTML | WPF_AUTOINLINE;
|
|
|
|
// Create the root moniker
|
|
CHECKHR(hr = pActiveUrl->CreateWebPage(NULL, &Options, 0, ppmkNew));
|
|
|
|
// QI for the requested object iid
|
|
CHECKHR(hr = pActiveUrl->BindToObject(riid, ppvObject));
|
|
|
|
// Don't Keep Alive, assume ppvObject controls the lifetime, not pActiveUrl
|
|
pActiveUrl->DontKeepAlive();
|
|
}
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pPersist);
|
|
SafeRelease(pMoniker);
|
|
SafeMemFree(pszRootUrl);
|
|
SafeMemFree(pszUrl);
|
|
SafeMemFree(pwszUrl);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Failed, return hr, otherwise, return MK_S_ASYNCHRONOUS if going async
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::ActiveObjectFromUrl - Called from CActiveUrlRequest::Start
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimeActiveUrlCache::ActiveObjectFromUrl(
|
|
/* in */ LPCSTR pszRootUrl,
|
|
/* in */ BOOL fCreate,
|
|
/* in */ REFIID riid,
|
|
/* out */ LPVOID *ppvObject,
|
|
/* out */ IUnknown **ppUnkKeepAlive)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPWSTR pwszUrl=NULL;
|
|
LPACTIVEURL pActiveUrl;
|
|
IMoniker *pMoniker=NULL;
|
|
IPersistMoniker *pPersist=NULL;
|
|
|
|
// Invalid Arg
|
|
if (NULL == pszRootUrl || NULL == ppvObject || (TRUE == fCreate && NULL == ppUnkKeepAlive))
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Better not start with mhtml:
|
|
Assert(StrCmpNI(pszRootUrl, "mhtml:", 6) != 0);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Try to resolve this url
|
|
if (FAILED(_ResolveUrl(pszRootUrl, &pActiveUrl)))
|
|
{
|
|
// NoCreate ?
|
|
if (FALSE == fCreate)
|
|
{
|
|
hr = TrapError(MIME_E_NOT_FOUND);
|
|
goto exit;
|
|
}
|
|
|
|
// Register an ActiveUrl
|
|
CHECKHR(hr = _RegisterUrl(NULL, (BINDF)0, &pActiveUrl));
|
|
|
|
// Convert pszRootUrl to a wide
|
|
CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszRootUrl));
|
|
|
|
// Create an Actual Url Moniker
|
|
CHECKHR(hr = CreateURLMoniker(NULL, pwszUrl, &pMoniker));
|
|
|
|
// Get an IPersistMoniker
|
|
CHECKHR(hr = pActiveUrl->BindToObject(IID_IPersistMoniker, (LPVOID *)&pPersist));
|
|
|
|
// Load the message with pmkOriginal
|
|
hr = pPersist->Load(FALSE, pMoniker, NULL, 0);
|
|
if (FAILED(hr) && E_PENDING != hr && MK_S_ASYNCHRONOUS != hr)
|
|
{
|
|
hr = TrapError(hr);
|
|
goto exit;
|
|
}
|
|
|
|
// Return the IUnknown Keep Alive Object
|
|
CHECKHR(hr = pActiveUrl->BindToObject(IID_IUnknown, (LPVOID *)ppUnkKeepAlive));
|
|
|
|
// Don't Keep Alive, assume ppvObject controls the lifetime, not pActiveUrl
|
|
pActiveUrl->DontKeepAlive();
|
|
}
|
|
|
|
// Return an Interface
|
|
CHECKHR(hr = pActiveUrl->BindToObject(riid, ppvObject));
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(pwszUrl);
|
|
SafeRelease(pMoniker);
|
|
SafeRelease(pPersist);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CMimeActiveUrlCache::RegisterActiveObject
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CMimeActiveUrlCache::RegisterActiveObject(
|
|
/* in */ LPCSTR pszRootUrl,
|
|
/* in */ LPMESSAGETREE pTree)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LPCSTR pszUrl;
|
|
LPACTIVEURL pActiveUrl;
|
|
|
|
// Invalid Arg
|
|
if (NULL == pszRootUrl || NULL == pTree)
|
|
return TrapError(E_INVALIDARG);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Better start with mhtml:
|
|
Assert(StrCmpNI(pszRootUrl, "mhtml:", 6) == 0);
|
|
|
|
// Fixup pszUrl
|
|
pszUrl = (pszRootUrl + 6);
|
|
|
|
// Better not already be running
|
|
if (SUCCEEDED(_ResolveUrl(pszUrl, &pActiveUrl)))
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Register an ActiveUrl
|
|
CHECKHR(hr = _RegisterUrl(pTree, (BINDF)0, &pActiveUrl));
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|