");
}
return hr;
}
HRESULT CFileListWrapper::GetItemInfo(long lResId, LPWSTR wszInfoDescCanonical, CComBSTR& bstrInfoDesc, CComBSTR& bstrInfo)
{
HRESULT hr = E_FAIL;
WCHAR wszInfoDesc[MAX_PATH];
LoadStringW(_Module.GetResourceInstance(), lResId, wszInfoDesc, ARRAYSIZE(wszInfoDesc));
bstrInfoDesc = wszInfoDesc;
if (m_spFolderItem2)
{
CComBSTR bstrInfoDescCanonical = wszInfoDescCanonical;
CComVariant var;
hr = m_spFolderItem2->ExtendedProperty(bstrInfoDescCanonical, &var);
if (SUCCEEDED(hr))
{
WCHAR wszTemp[80];
if (var.vt == VT_BSTR)
{
// Of the three types of data we care about one is dangerous. The BSTR data that
// we read from the file could contain HTML code which we would render in WebView.
// This could cause potential security problems. To get around this we sanatize
// the BSTR before we return it. We need to do the following replacements:
//
// original replace with
// < <
// > >
// " " <= this would be paranoid and isn't 100% critical
// ' ‘ <= this would be paranoid and isn't 100% critical
LPWSTR psz = var.bstrVal;
LPWSTR pszBad;
if (psz == NULL)
{
// we probably cant depend on hr and the out param matching (since this is
// scriptable and therefore must return success)
psz = L"";
}
while (pszBad = StrPBrkW(psz, L"<>"))
{
// store the bad character
WCHAR chBadChar = *pszBad;
// null the string
*pszBad = NULL;
// add the good part of the string, if there is any
if ( *psz )
bstrInfo += psz;
// based on which bad character we found add the correct HTLM special character code
switch ( chBadChar )
{
case L'<':
bstrInfo += L"<";
break;
case L'>':
bstrInfo += L">";
break;
}
// Advance the psz pointer. Note it might be an empty string after this.
psz = pszBad+1;
}
// Add the remaining portion of the good string, even if it's an empty string.
// bstrInfo is passed in uninitialized so we need to set it to something even
// if that something is an empty string.
bstrInfo += psz;
}
else if (var.vt == VT_DATE)
{
SYSTEMTIME st;
FILETIME ft;
if (VariantTimeToSystemTime(var.date, &st)
&& SystemTimeToFileTime(&st, &ft)
&& SHFormatDateTimeW(&ft, &m_dwDateFlags, wszTemp, ARRAYSIZE(wszTemp)))
{
bstrInfo += wszTemp;
}
else
{
hr = E_FAIL;
}
}
else if (var.vt == VT_UI8 && StrCmpIW(wszInfoDescCanonical, L"size") == 0)
{
StrFormatByteSize64(var.ullVal, wszTemp, ARRAYSIZE(wszTemp));
bstrInfo += wszTemp;
}
else
{
hr = E_FAIL;
}
}
}
return hr;
}
HRESULT CFileListWrapper::NoneSelected()
{
WCHAR wszIntro[MAX_PATH];
CComPtr spFolderItem;
if (!m_bCSCDisplayed)
{
CSCShowStatusInfo();
m_bCSCDisplayed = TRUE;
}
if (m_spFolderItems->Item(CComVariant(0), &spFolderItem) == S_OK)
{ // This filelist has atleast one item.
IfFalseRet(LoadStringW(_Module.GetResourceInstance(), IDS_PROMPT, wszIntro, ARRAYSIZE(wszIntro)), E_FAIL);
}
else
{
IfFalseRet(LoadStringW(_Module.GetResourceInstance(), IDS_EMPTY, wszIntro, ARRAYSIZE(wszIntro)), E_FAIL);
}
m_bstrInfoHTML += wszIntro;
spFolderItem = NULL;
if (SUCCEEDED(m_spFolder2->get_Self(&spFolderItem)))
{
m_spFolderItem = spFolderItem;
m_spFolderItem->QueryInterface(IID_FolderItem2, (void **)&m_spFolderItem2);
m_bFoundAuthor = FALSE;
m_bFoundComment = FALSE;
// Get the comment for the item
GetItemComment();
GetItemHTMLInfoTip();
DealWithDriveInfo();
GetCrossLinks();
m_spFolderItem2 = NULL;
m_spFolderItem = NULL;
}
return S_OK;
}
#define MAX_SELECTEDFILES_FOR_COMPUTING_SIZE 100
#define MAX_SELECTEDFILES_FOR_DISPLAYING_NAMES 16
HRESULT CFileListWrapper::MultipleSelected(long cSelection)
{
HRESULT hr = S_FALSE;
if (cSelection > 1)
{
WCHAR wszTemp[MAX_PATH];
wnsprintfW(wszTemp, ARRAYSIZE(wszTemp), L"%ld", cSelection);
m_bstrInfoHTML += wszTemp;
IfFalseRet(LoadStringW(_Module.GetResourceInstance(), IDS_MULTIPLE, wszTemp, ARRAYSIZE(wszTemp)), E_FAIL);
m_bstrInfoHTML += wszTemp;
if (cSelection <= MAX_SELECTEDFILES_FOR_COMPUTING_SIZE)
{
m_bstrInfoHTML += OLESTR("
");
CComPtr spFolderItem;
long lSize = 0;
for (int i = 0; i < cSelection; i++)
{
long lTempSize;
if (SUCCEEDED(m_spFolderItems->Item(CComVariant(i), &spFolderItem)))
{
if (SUCCEEDED(spFolderItem->get_Size(&lTempSize)))
{
lSize += lTempSize;
}
spFolderItem = NULL;
}
}
if (lSize > 0L)
{
IfFalseRet(LoadStringW(_Module.GetResourceInstance(), IDS_FILESIZE, wszTemp, ARRAYSIZE(wszTemp)), E_FAIL);
m_bstrInfoHTML += wszTemp;
StrFormatByteSizeW(lSize, wszTemp, ARRAYSIZE(wszTemp));
m_bstrInfoHTML += wszTemp;
m_bstrInfoHTML += OLESTR("
");
}
if (cSelection <= MAX_SELECTEDFILES_FOR_DISPLAYING_NAMES)
{
CComBSTR bstrTemp;
for (int i = 0; i < cSelection; i++)
{
if (SUCCEEDED(m_spFolderItems->Item(CComVariant(i), &spFolderItem)))
{
if (SUCCEEDED(spFolderItem->get_Name(&bstrTemp)))
{
m_bstrInfoHTML += " ";
m_bstrInfoHTML += bstrTemp;
bstrTemp.Empty();
}
spFolderItem = NULL;
}
}
}
}
hr = S_OK;
}
return hr;
}
HRESULT CFileListWrapper::OneSelected()
{
HRESULT hr = E_FAIL;
m_bFoundAuthor = FALSE;
m_bFoundComment = FALSE;
// Get the name of the item, making it a hyper-link if appropriate.
GetItemNameForDisplay();
// Get the type of the item
GetItemType();
if (!m_bPathIsSlow)
{
// Get the comment for the item
GetItemComment();
// Get the HTMLInfoTip
GetItemHTMLInfoTip();
// Get the date/time stamp on the item
GetItemDateTime();
// Get the size of the item
GetItemSize();
// Get the attributes (hidden, RO etc.) of the item
GetItemAttributes();
// Get the author of the document
GetItemAuthor();
DealWithDriveInfo();
}
hr = S_OK;
return hr;
}
HRESULT CFileListWrapper::OnCSCClick()
{
HRESULT hres = E_FAIL;
CComPtr spFolder;
CComPtr spFolder2;
if (m_spFileList && SUCCEEDED(m_spFileList->get_Folder(&spFolder))
&& SUCCEEDED(spFolder->QueryInterface(IID_Folder2, (void **)&spFolder2)))
{
m_spFolder2 = spFolder2;
hres = CSCShowStatus_FoldExpand_Toggle();
m_spFolder2 = NULL;
}
return S_OK;
}
HRESULT CFileListWrapper::OnCSCMouseOnOff(BOOL fOn)
{
CComPtr psPlusMin;
CComPtr psText;
HRESULT hres = E_FAIL;
// If we're already in this state don't do anything
if (m_bHotTracked == fOn)
return S_OK;
// If we receive a 'mouse on' but the element is not one we want to track or if we receive a 'mouse off' but
// the mouse is over one of our other elements that we want to hot track then don't do anything.
if (m_spWindow)
{
CComPtr phtmlevent;
CComPtr phtmlelement;
CComBSTR bstrId;
if (SUCCEEDED(m_spWindow->get_event(&phtmlevent)) && phtmlevent)
{
HRESULT hres;
if (!fOn)
hres = phtmlevent->get_toElement(&phtmlelement);
else
hres = phtmlevent->get_srcElement(&phtmlelement);
if (SUCCEEDED(hres) && phtmlelement && SUCCEEDED(phtmlelement->get_id(&bstrId)) && (bstrId.Length() > 0))
{
BOOL bContainsCSC;
bContainsCSC = (StrStrIW(bstrId, L"CSC") != NULL);
if (bContainsCSC != fOn)
return S_OK;
}
}
}
if (m_spCSCPlusMin && m_spCSCText && SUCCEEDED(hres = m_spCSCPlusMin->get_style(&psPlusMin)) && SUCCEEDED(hres = m_spCSCText->get_style(&psText)))
{
CComVariant vcolorBlack (OLESTR("black"));
CComBSTR bstrCSCPlusMin;
LPOLESTR pstrCursor = (fOn ? OLESTR("hand") : OLESTR("auto"));
CComVariant vcolorLink;
m_bHotTracked = fOn;
m_spDocument->get_linkColor(&vcolorLink);
if (m_bExpanded)
bstrCSCPlusMin = fOn ? CSC_MINUSHOT : CSC_MINUSCOLD;
else
bstrCSCPlusMin = fOn ? CSC_PLUSHOT : CSC_PLUSCOLD;
m_spCSCPlusMin->put_innerHTML(bstrCSCPlusMin);
psPlusMin->put_cursor(pstrCursor);
psText->put_color(fOn ? vcolorLink : vcolorBlack);
psText->put_cursor(pstrCursor);
}
return hres;
}
HRESULT CFileListWrapper::CSCSynchronize()
{
HRESULT hres = E_FAIL;
CComPtr spFolder;
CComPtr spFolder2;
if (m_spFileList && SUCCEEDED(m_spFileList->get_Folder(&spFolder))
&& SUCCEEDED(spFolder->QueryInterface(IID_Folder2, (void **)&spFolder2)))
{
hres = spFolder2->Synchronize();
}
return hres;
}
const UINT c_ids_uiCSCText[] =
{IDS_CSC_ONLINE, IDS_CSC_OFFLINE, IDS_CSC_SERVERAVAILABLE, IDS_CSC_DIRTYCACHE};
HRESULT CFileListWrapper::CSCGetStatusText(LONG lStatus, CComBSTR& bstrCSCText)
{
WCHAR wszTemp[MAX_PATH];
if ((lStatus >= 0) && (lStatus < ARRAYSIZE(c_ids_uiCSCText))
&& LoadStringW(_Module.GetResourceInstance(), c_ids_uiCSCText[(int)lStatus], wszTemp, ARRAYSIZE(wszTemp)))
{
bstrCSCText += wszTemp;
}
return S_OK;
}
const UINT c_ids_uiCSCDetail[] =
{IDS_CSC_DETAIL_ONLINE, IDS_CSC_DETAIL_OFFLINE, IDS_CSC_DETAIL_SERVERAVAILABLE, IDS_CSC_DETAIL_DIRTYCACHE};
HRESULT CFileListWrapper::CSCGetStatusDetail(LONG lStatus, CComBSTR& bstrCSCDetail)
{
WCHAR wszTemp[MAX_PATH];
if ((lStatus >= 0) && (lStatus < ARRAYSIZE(c_ids_uiCSCDetail))
&& LoadStringW(_Module.GetResourceInstance(), c_ids_uiCSCDetail[(int)lStatus], wszTemp, ARRAYSIZE(wszTemp)))
{
bstrCSCDetail += wszTemp;
}
return S_OK;
}
#define CSC_STATUS_ONLINE 0
#define CSC_STATUS_OFFLINE 1
#define CSC_STATUS_SERVERAVAILABLE 2
#define CSC_STATUS_DIRTYCACHE 3
HRESULT CFileListWrapper::CSCGetStatusButton(LONG lStatus, CComBSTR& bstrCSCButton)
{
if ((lStatus == CSC_STATUS_SERVERAVAILABLE) || (lStatus == CSC_STATUS_DIRTYCACHE))
{
bstrCSCButton += OLESTR("
");
}
return S_OK;
}
HRESULT CFileListWrapper::GetCSCFolderStatus(LONG* plStatus)
{
return m_spFolder2 ? m_spFolder2->get_OfflineStatus(plStatus) : E_FAIL;
}
HRESULT CFileListWrapper::CSCShowStatusInfo()
{
LONG lStatus;
if (m_spCSCText && m_spCSCPlusMin && m_spCSCDetail && m_spCSCButton && m_spCSCStyle
&& m_spCSCDetailStyle && m_spCSCButtonStyle)
{
CComBSTR bstrCSC_Display;
if (SUCCEEDED(GetCSCFolderStatus(&lStatus)) && (lStatus >= 0))
{
CComBSTR bstrCSCText;
CSCGetStatusText(lStatus, bstrCSCText);
bstrCSCText += OLESTR(" ");
CComBSTR bstrCSCPlusMin;
CComBSTR bstrCSCDetail;
CComBSTR bstrCSCDetail_Display;
if (m_bExpanded)
{
bstrCSCPlusMin = m_bHotTracked ? CSC_MINUSHOT : CSC_MINUSCOLD;
bstrCSCText += OLESTR(" ");
CSCGetStatusDetail(lStatus, bstrCSCDetail);
bstrCSCDetail += OLESTR(" ");
bstrCSCDetail_Display = OLESTR("");
if (m_bRTLDocument)
{
// [msadek]; Life would be easier if the object model has exposed
// right offset through get_offsetRight().
CComPtr spDocBody = NULL;
long lOffsetLeft, lOffsetWidth, lClientWidth, lOffsetRight = 0;
if (SUCCEEDED(m_spCSCText->QueryInterface(IID_IHTMLControlElement, (void **)&spDocBody))
&& SUCCEEDED(m_spCSCText->get_offsetLeft(&lOffsetLeft))
&& SUCCEEDED(m_spCSCText->get_offsetWidth(&lOffsetWidth))
&& SUCCEEDED(spDocBody->get_clientWidth(&lClientWidth)))
{
lOffsetRight = lClientWidth - (lOffsetLeft + lOffsetWidth);
}
m_spCSCDetailStyle->put_marginRight(CComVariant(lOffsetRight - 10L));
}
else
{
long lOffsetLeft;
if (FAILED(m_spCSCText->get_offsetLeft(&lOffsetLeft)))
{
lOffsetLeft = 0;
}
m_spCSCDetailStyle->put_marginLeft(CComVariant(lOffsetLeft - 10L));
}
}
else
{
bstrCSCPlusMin = m_bHotTracked ? CSC_PLUSHOT : CSC_PLUSCOLD;
bstrCSCDetail += OLESTR("");
bstrCSCDetail_Display = OLESTR("none");
}
m_spCSCPlusMin->put_innerHTML(bstrCSCPlusMin);
m_spCSCText->put_innerHTML(bstrCSCText);
m_spCSCDetail->put_innerHTML(bstrCSCDetail);
m_spCSCDetailStyle->put_display(bstrCSCDetail_Display);
CComBSTR bstrCSCButton_Display;
CComBSTR bstrCSCButton;
if (SUCCEEDED(CSCGetStatusButton(lStatus, bstrCSCButton)) && (bstrCSCButton.Length() > 0))
{
bstrCSCButton_Display = OLESTR("");
}
else
{
bstrCSCButton = OLESTR("");
bstrCSCButton_Display = OLESTR("none");
}
m_spCSCButton->put_innerHTML(bstrCSCButton);
m_spCSCButtonStyle->put_display(bstrCSCButton_Display);
bstrCSC_Display = OLESTR("");
}
else
{
bstrCSC_Display = OLESTR("none");
}
m_spCSCStyle->put_display(bstrCSC_Display);
}
return S_OK;
}
HRESULT CFileListWrapper::CSCShowStatus_FoldExpand_Toggle()
{
m_bExpanded = !m_bExpanded;
return (CSCShowStatusInfo());
}
// fEnter true for mouseover, focus; false for mouseout, blur
HRESULT CFileListWrapper::OnWebviewLinkEvent( BOOL fEnter )
{
CComPtr spEvent;
CComPtr spAnchor;
HRESULT hr;
// NT# 354743, IHTMLEventObj::get_event() can return S_OK and
// not set the out param, so we need to protect against that.
spEvent = NULL;
hr = m_spWindow->get_event(&spEvent);
// Automation interfaces sometimes return S_FALSE on failures to prevent scripting errors
if (S_OK == hr)
{
// Sometimes Trident will not set the out parameter when it returns S_OK, so
// we need to make sure it's not NULL.
if (spEvent)
{
hr = GetEventAnchorElement(spEvent, &spAnchor);
}
else
hr = E_FAIL;
if (S_OK == hr)
{
if (fEnter)
{
CComBSTR bstrTitle;
hr = spAnchor->get_title(&bstrTitle);
if(SUCCEEDED(hr))
{
m_spWindow->put_status(bstrTitle);
}
spEvent->put_returnValue(CComVariant(true));
}
else
{
hr = m_spWindow->put_status(OLESTR(""));
}
}
}
return S_OK;
}
// Walks up the component chain from the event source, looking for
// an anchor element. Returns S_OK if successful, some error otherwise.
// On failure *ppElt will be set to null. Note that this gives back
// the IHTMLElement that corresponds to the anchor, not the
// IHTMLAnchorElement, as only IHTMLElement has get_title
HRESULT CFileListWrapper::GetEventAnchorElement( IHTMLEventObj *pEvent,
IHTMLElement **ppElt )
{
CComPtr spElement;
*ppElt = NULL;
if( SUCCEEDED( pEvent->get_srcElement( &spElement )))
{
BOOL fContinue = TRUE;
while( fContinue && spElement )
{
CComPtr spAnchor;
if( SUCCEEDED( spElement->QueryInterface( IID_IHTMLAnchorElement,
reinterpret_cast( &spAnchor ))))
{
fContinue = false;
*ppElt = spElement;
reinterpret_cast( *ppElt )->AddRef();
}
else
{
IHTMLElement *pIElt = NULL;
if( SUCCEEDED( spElement->get_parentElement( &pIElt )))
{
spElement = pIElt;
if (pIElt)
{
pIElt->Release();
}
}
else
{
spElement.Release();
}
}
}
}
return ( *ppElt ? S_OK : E_FAIL );
}
// Bind to the connection points for each of the link elements
// contained within m_spLinks. The advise cookie for each link
// is stored as an attribute within the link, so we don't need
// to maintain a mapping between links and elements.
// fAdvise -- true to make connections, false to break
HRESULT CFileListWrapper::AdviseWebviewLinks( BOOL fAdvise)
{
CComPtr spDisp;
CComPtr spElement;
CComPtr spCollection;
CComVariant vtEmpty;
CComBSTR bstrAttr = WV_LINKNAME;
long cLinks;
DWORD dwCookie;
HRESULT hr;
IfFailRet( GetWVLinksCollection( &spCollection, &cLinks ));
for( long i = 0; i < cLinks; i++ )
{
hr = spCollection->item( CComVariant( i ), vtEmpty, &spDisp );
if (!spDisp)
{
hr = E_FAIL;
}
if( SUCCEEDED( hr ))
{
hr = spDisp->QueryInterface( IID_IHTMLElement,
reinterpret_cast( &spElement ));
spDisp.Release();
}
if( SUCCEEDED( hr ))
{
if( fAdvise )
{
hr = AtlAdvise( spElement, this, IID_IDispatch, &dwCookie );
if( SUCCEEDED( hr ))
{
hr = spElement->setAttribute( bstrAttr,
CComVariant( static_cast( dwCookie )),
VARIANT_FALSE );
if( FAILED( hr ))
{
AtlUnadvise( spElement, IID_IDispatch, dwCookie );
}
}
}
else
{
CComVariant vtCookie;
hr = spElement->getAttribute( bstrAttr, FALSE, &vtCookie );
if( SUCCEEDED( hr ))
{
dwCookie = static_cast( vtCookie.lVal );
AtlUnadvise( spElement, IID_IDispatch, dwCookie );
}
}
spElement.Release();
}
}
return S_OK;
}
// Get the IHTMLElementCollection that holds the named links
HRESULT CFileListWrapper::GetWVLinksCollection( IHTMLElementCollection **ppCollection,
long *pcLinks )
{
CComPtr spDisp;
CComPtr spCollection;
CComVariant vtEmpty;
HRESULT hr;
ASSERT( ppCollection );
ASSERT( pcLinks );
*ppCollection = NULL;
*pcLinks = 0;
if (!m_spLinks) return E_FAIL;
// Get the initial element collection from m_spLinks
IfFailRet( m_spLinks->get_all( &spDisp ));
IfFailRet( spDisp->QueryInterface( IID_IHTMLElementCollection,
reinterpret_cast( &spCollection )));
spDisp.Release();
// Get the collection of elements with our linkname. If nothing exists, spDisp
// will be null and item returns S_OK.
IfFailRet( spCollection->item( CComVariant( WV_LINKNAME ), vtEmpty, &spDisp ));
if( !spDisp ) return E_FAIL;
IfFailRet( spDisp->QueryInterface( IID_IHTMLElementCollection,
reinterpret_cast( ppCollection )));
return reinterpret_cast( *ppCollection )->get_length( pcLinks );
}