windows-nt/Source/XPSP1/NT/shell/ext/shimgvw/prevctrl.cpp

568 lines
16 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "precomp.h"
#include <shimgvw.h>
#include "PrevCtrl.h"
#include "autosecurity.h"
#include <dispex.h>
#pragma hdrstop
LRESULT CPreview::OnCreate(UINT , WPARAM , LPARAM , BOOL&)
{
ATLTRACE(_T("CPreview::OnCreate\n"));
// Create the preview window
RECT rcWnd;
GetClientRect(&rcWnd);
if (m_cwndPreview.Create(m_hWnd, rcWnd, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0))
{
m_cwndPreview.SetNotify(this);
HPALETTE hpal;
if (SUCCEEDED(GetAmbientPalette(hpal)))
m_cwndPreview.SetPalette(hpal);
return 0;
}
return -1;
}
LRESULT CPreview::OnActivate(UINT , WPARAM , LPARAM , BOOL& bHandled)
{
ATLTRACE(_T("CPreview::OnActivate\n"));
m_cwndPreview.SetFocus();
bHandled = false;
return 0;
}
HRESULT CPreview::OnDrawAdvanced(ATL_DRAWINFO&)
{
ATLTRACE(_T("CPreview::OnDrawAdvanced\n"));
return S_OK;
}
LRESULT CPreview::OnEraseBkgnd(UINT , WPARAM , LPARAM , BOOL&)
{
ATLTRACE(_T("CPreview::OnEraseBkgnd\n"));
return TRUE;
}
LRESULT CPreview::OnSize(UINT , WPARAM , LPARAM lParam, BOOL&)
{
ATLTRACE(_T("CPreview::OnSize\n"));
::SetWindowPos(m_cwndPreview.m_hWnd, NULL, 0,0,
LOWORD(lParam), HIWORD(lParam), SWP_NOZORDER | SWP_NOACTIVATE);
return 0;
}
// IObjectSafety::GetInterfaceSafetyOptions
//
// This method never gets called. We are safe for any and every thing. There should
// be no possible way that this control could lose, destroy, or expose data.
STDMETHODIMP CPreview::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions,
DWORD *pdwEnabledOptions)
{
ATLTRACE(_T("IObjectSafetyImpl::GetInterfaceSafetyOptions\n"));
HRESULT hr;
hr = IObjectSafetyImpl<CPreview, INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA>::GetInterfaceSafetyOptions(riid, pdwSupportedOptions, pdwEnabledOptions);
if (SUCCEEDED(hr))
{
IsHostLocalZone(CAS_REG_VALIDATION, &hr);
}
return hr;
}
STDMETHODIMP CPreview::SetInterfaceSafetyOptions(REFIID riid, DWORD dwSupportedOptions,
DWORD dwEnabledOptions)
{
ATLTRACE(_T("IObjectSafetyImpl::SetInterfaceSafetyOptions\n"));
HRESULT hr;
hr = IObjectSafetyImpl<CPreview, INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA>::SetInterfaceSafetyOptions(riid, dwSupportedOptions, dwEnabledOptions);
if (SUCCEEDED(hr))
{
IsHostLocalZone(CAS_REG_VALIDATION, &hr);
}
return hr;
}
// IPersistPropertyBag::Load
//
// We have the following properties that we can load from the property bag:
// Toolbar false/zero = don't show the toolbar, otherwise show the toolbar
// Full Screen false/zero = don't show fullscreen button on toolbar, otherwise show the button
// Context Menu false/zero = don't show context menu, otherwise show the context menu when the user right clicks
// Print Button false/zero = don't show print button on toolbar, otherwise show the button
STDMETHODIMP CPreview::Load(IPropertyBag * pPropBag, IErrorLog * pErrorLog)
{
HRESULT hr;
VARIANT var;
BOOL bDummy = TRUE;
var.vt = VT_UI4;
var.ulVal = TRUE;
hr = pPropBag->Read(L"Toolbar", &var, NULL);
if (SUCCEEDED(hr) && var.vt==VT_UI4)
{
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_TOOLBAR,var.ulVal,bDummy);
}
var.vt = VT_UI4;
var.ulVal = TRUE;
hr = pPropBag->Read(L"Full Screen", &var, NULL);
if (SUCCEEDED(hr) && var.vt==VT_UI4)
{
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_FULLSCREENBTN,var.ulVal,bDummy);
}
var.vt = VT_UI4;
var.ulVal = TRUE;
hr = pPropBag->Read(L"Print Button", &var, NULL);
if (SUCCEEDED(hr) && var.vt==VT_UI4)
{
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_PRINTBTN,var.ulVal,bDummy);
}
var.vt = VT_UI4;
var.ulVal = TRUE;
hr = pPropBag->Read(L"Context Menu", &var, NULL);
if (SUCCEEDED(hr) && var.vt==VT_UI4)
{
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_CONTEXTMENU,var.ulVal,bDummy);
}
var.vt = VT_UI4;
var.ulVal = FALSE;
hr = pPropBag->Read(L"Allow Online", &var, NULL);
if (SUCCEEDED(hr) && var.vt==VT_UI4)
{
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_ALLOWGOONLINE,var.ulVal,bDummy);
}
var.vt = VT_UI4;
var.ulVal = FALSE;
hr = pPropBag->Read(L"Disable Edit", &var, NULL);
if (SUCCEEDED(hr) && var.vt==VT_UI4)
{
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_DISABLEEDIT,var.ulVal,bDummy);
}
return S_OK;
}
// If we are initialized via IStream, read a DWORD from the stream that is a mask
// for which toolbar buttons to show
STDMETHODIMP CPreview::Load(IStream *pStream)
{
DWORD dwFlags = 0;
ULONG ulRead = 0;
BOOL bDummy = TRUE;
if (SUCCEEDED(pStream->Read(&dwFlags, sizeof(dwFlags), &ulRead)) && ulRead == sizeof(dwFlags))
{
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_TOOLBAR,dwFlags & PVTB_TOOLBAR, bDummy);
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_FULLSCREENBTN,dwFlags & PVTB_HIDEFULLSCREEN, bDummy);
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_PRINTBTN,dwFlags & PVTB_HIDEPRINTBTN, bDummy);
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_CONTEXTMENU,dwFlags & PVTB_CONTEXTMENU, bDummy);
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_ALLOWGOONLINE,dwFlags & PVTB_ALLOWONLINE, bDummy);
m_cwndPreview.IV_OnSetOptions(IV_SETOPTIONS,IVO_DISABLEEDIT,dwFlags & PVTB_DISABLEEDIT, bDummy);
}
return S_OK;
}
// IPreview Methods:
STDMETHODIMP CPreview::ShowFile(BSTR bstrFileName)
{
m_cwndPreview.ShowFile(bstrFileName, 1);
return S_OK;
}
STDMETHODIMP CPreview::ShowFile(BSTR bstrFileName, int iSelectCount)
{
m_cwndPreview.ShowFile(bstrFileName, iSelectCount);
return S_OK;
}
STDMETHODIMP CPreview::Show(VARIANT var)
{
HRESULT hr;
switch (var.vt)
{
case VT_UNKNOWN:
case VT_DISPATCH:
// QI for Folder Item
if (var.punkVal)
{
FolderItems *pfis;
FolderItem *pfi;
hr = var.punkVal->QueryInterface(IID_PPV_ARG(FolderItem, &pfi));
if (SUCCEEDED(hr))
{
// If the item is a link we want to get the link's target:
VARIANT_BOOL vbool;
hr = pfi->get_IsLink(&vbool);
if (SUCCEEDED(hr) && (VARIANT_FALSE != vbool)) // IsLink returns TRUE, not VARIANT_TRUE
{
IDispatch *pdisp;
hr = pfi->get_GetLink(&pdisp);
if (SUCCEEDED(hr) && pdisp)
{
IShellLinkDual2 * psl2;
hr = pdisp->QueryInterface(IID_PPV_ARG(IShellLinkDual2, &psl2));
if (SUCCEEDED(hr) && psl2)
{
FolderItem * pfiTarg;
hr = psl2->get_Target(&pfiTarg);
if (SUCCEEDED(hr) && pfiTarg)
{
pfi->Release();
pfi = pfiTarg;
}
psl2->Release();
}
pdisp->Release();
}
}
// Now we need to know the path for this item. We can only view items if
// we can get a path or URL to the target so some namespaces aren't viewable.
BSTR bstr;
hr = pfi->get_Path(&bstr);
if (SUCCEEDED(hr))
{
m_cwndPreview.ShowFile(bstr, 1);
SysFreeString(bstr);
hr = S_OK;
}
else
{
// we couldn't get the path so we will display the "No Preview" message
m_cwndPreview.ShowFile(NULL, 1);
hr = S_FALSE;
}
// now release the Folder Item pointer
pfi->Release();
return hr;
}
else if (SUCCEEDED(var.punkVal->QueryInterface(IID_PPV_ARG(FolderItems, &pfis))))
{
// currently in the multi-select case we just show the multi-select message.
// eventually this should go to slideshow mode
m_cwndPreview.ShowFile(NULL, 2);
pfis->Release();
return S_FALSE;
}
}
// the unknown pointer isn't for an object type that we know about
return E_INVALIDARG;
case VT_BSTR:
m_cwndPreview.ShowFile(var.bstrVal, 1);
break;
case VT_BOOL:
// show(false) will hide the currently previewed item
if (VARIANT_FALSE == var.boolVal)
{
m_cwndPreview.ShowFile(NULL, 0);
return S_OK;
}
else
{
return E_INVALIDARG;
}
default:
return E_INVALIDARG;
}
return S_OK;
}
//*** IsVK_TABCycler -- is key a TAB-equivalent
// ENTRY/EXIT
// dir 0 if not a TAB, non-0 if a TAB
// NOTES
// NYI: -1 for shift+tab, 1 for tab
// cloned from browseui/util.cpp
//
int IsVK_TABCycler(MSG *pMsg)
{
if (!pMsg)
return 0;
if (pMsg->message != WM_KEYDOWN)
return 0;
if (! (pMsg->wParam == VK_TAB || pMsg->wParam == VK_F6))
return 0;
#if 0 // todo?
return (GetAsyncKeyState(VK_SHIFT) < 0) ? -1 : 1;
#endif
return 1;
}
//***
// NOTES
// hard-coded 1/2/4 (vs. KEYMOD_*) is same thing atlctl.h does. go figure...
DWORD GetGrfMods()
{
DWORD dwMods;
dwMods = 0;
if (GetAsyncKeyState(VK_SHIFT) < 0)
dwMods |= 1; // KEYMOD_SHIFT
if (GetAsyncKeyState(VK_CONTROL) < 0)
dwMods |= 2; // KEYMOD_CONTROL
if (GetAsyncKeyState(VK_MENU) < 0)
dwMods |= 4; // KEYMOD_MENU
return dwMods;
}
STDMETHODIMP CPreview::TranslateAccelerator(LPMSG lpmsg)
{
ATLTRACE(_T("CPreview::TranslateAccelerator\n"));
if (m_cwndPreview.TranslateAccelerator(lpmsg))
{
return S_OK;
}
if (IsVK_TABCycler(lpmsg))
{
// REVIEW: looks like newer versions of ATL might do this for us so
// possibly we can replace w/ call to SUPER::TA when we upgrade.
CComQIPtr <IOleControlSite, &IID_IOleControlSite> spOCS(m_spClientSite);
if (spOCS) {
return spOCS->TranslateAccelerator(lpmsg, GetGrfMods());
}
}
return S_FALSE;
}
STDMETHODIMP CPreview::OnFrameWindowActivate(BOOL fActive)
{
if (fActive)
{
m_cwndPreview.SetFocus();
}
return S_OK;
}
LRESULT CPreview::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
ATLTRACE(_T("CPreview::OnSetFocus\n"));
LRESULT ret = CComControl<CPreview>::OnSetFocus(uMsg,wParam,lParam, bHandled);
m_cwndPreview.SetFocus();
return ret;
}
STDMETHODIMP CPreview::get_printable(BOOL * pVal)
{
// If we don't trust the host, we tell them it is always printable because we don't
// want them to be able to see if the file exists on the disk. Hackers can use
// this to determine where the OS is installed and which apps are installed.
*pVal = TRUE;
if (IsHostLocalZone(CAS_REG_VALIDATION, NULL))
{
*pVal = m_cwndPreview.GetPrintable();
}
return S_OK;
}
STDMETHODIMP CPreview::put_printable(BOOL newVal)
{
return S_FALSE;
}
STDMETHODIMP CPreview::get_cxImage(long * pVal)
{
// REVIEW: Return an error and set output to zero if no image is currently displayed?
*pVal = m_cwndPreview.m_ctlPreview.m_cxImage;
return S_OK;
}
STDMETHODIMP CPreview::get_cyImage(long * pVal)
{
// REVIEW: Return an error and set output to zero if no image is currently displayed?
*pVal = m_cwndPreview.m_ctlPreview.m_cyImage;
return S_OK;
}
STDMETHODIMP CPreview::Zoom(int iDirection)
{
switch (iDirection)
{
case -1:
m_cwndPreview.ZoomOut();
break;
case 0:
return S_OK;
case 1:
m_cwndPreview.ZoomIn();
break;
default:
return S_FALSE;
}
return S_OK;
}
STDMETHODIMP CPreview::BestFit()
{
m_cwndPreview.BestFit();
return S_OK;
}
STDMETHODIMP CPreview::ActualSize()
{
m_cwndPreview.ActualSize();
return S_OK;
}
STDMETHODIMP CPreview::SlideShow()
{
HRESULT hr = m_cwndPreview.StartSlideShow(NULL);
return SUCCEEDED(hr) ? S_OK : S_FALSE;
}
STDMETHODIMP CPreview::Rotate(DWORD dwAngle)
{
HRESULT hr = m_cwndPreview.Rotate(dwAngle);
return SUCCEEDED(hr) ? S_OK : S_FALSE;
}
STDMETHODIMP CPreview::SetClientSite(IOleClientSite *pClientSite)
{
IOleObjectImpl<CPreview>::SetClientSite(pClientSite);
m_cwndPreview.SetSite(pClientSite);
return S_OK;
}
STDMETHODIMP CPreview::SetSite(IUnknown* punkSite)
{
IObjectWithSiteImpl<CPreview>::SetSite(punkSite);
m_cwndPreview.SetSite(punkSite);
if (punkSite)
{
if (!_pfv)
{
IShellView *psv;
if (SUCCEEDED(IUnknown_QueryService(punkSite, SID_DefView, IID_PPV_ARG(IShellView, &psv))))
{
IDispatch *pdisp;
if (SUCCEEDED(psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARG(IDispatch, &pdisp))))
{
ConnectToConnectionPoint(SAFECAST(this, IPreview2 *), DIID_DShellFolderViewEvents, TRUE, pdisp, &_dwConnectionCookie, NULL);
_ProcessSelection();
pdisp->Release();
}
psv->QueryInterface(IID_PPV_ARG(IFolderView, &_pfv)); // capture this
psv->Release();
}
}
}
else
{
ATOMICRELEASE(_pfv); // break ref cycle
}
return S_OK;
}
STDMETHODIMP CPreview::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams,
VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
HRESULT hr = S_OK;
if (dispidMember == DISPID_FOCUSCHANGED)
{
hr = _ProcessSelection();
}
else
{
hr = CStockPropImpl<CPreview, IPreview2, &IID_IPreview2, &LIBID_PREVIEWLib>::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
}
return hr;
}
STDMETHODIMP CPreview::SetWallpaper(BSTR bstrPath)
{
return m_cwndPreview.SetWallpaper(bstrPath);
}
STDMETHODIMP CPreview::SaveAs(BSTR bstrPath)
{
return m_cwndPreview.SaveAs(bstrPath);
}
BOOL CPreview::IsHostLocalZone(DWORD dwFlags, HRESULT * phr)
{
HRESULT hr = E_ACCESSDENIED;
CComPtr<IDefViewSafety> spDefViewSafety;
if (SUCCEEDED(IUnknown_QueryService(m_spClientSite, SID_SFolderView,
IID_PPV_ARG(IDefViewSafety, &spDefViewSafety))))
{
hr = spDefViewSafety->IsSafePage();
}
if (phr)
{
*phr = hr;
}
return (S_OK == hr) ? TRUE : FALSE;
}
STDMETHODIMP CPreview::_ProcessSelection(void)
{
if (_pfv)
{
int iItem;
if (S_OK == _pfv->GetFocusedItem(&iItem))
{
LPITEMIDLIST pidlFile;
if (SUCCEEDED(_pfv->Item(iItem, &pidlFile)))
{
IShellFolder *psf;
if (SUCCEEDED(_pfv->GetFolder(IID_PPV_ARG(IShellFolder, &psf))))
{
TCHAR szPath[MAX_PATH];
if (SUCCEEDED(DisplayNameOf(psf, pidlFile, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath))))
{
ShowFile(szPath, 1);
}
psf->Release();
}
ILFree(pidlFile);
}
}
else
{
ShowFile(NULL, 0);
}
}
return S_OK;
}