windows-nt/Source/XPSP1/NT/shell/ext/webvw/thumbctl.cpp
2020-09-26 16:20:57 +08:00

910 lines
28 KiB
C++

// ThumbCtl.cpp : Implementation of CThumbCtl
#include "priv.h"
#include "shdguid.h"
const CLSID CLSID_ThumbCtlOld = {0x1d2b4f40,0x1f10,0x11d1,{0x9e,0x88,0x00,0xc0,0x4f,0xdc,0xab,0x92}}; // retired from service, so made private
// global
// for LoadLibrary/GetProcAddress on SHGetDiskFreeSpaceA
typedef BOOL (__stdcall * PFNSHGETDISKFREESPACE)(LPCTSTR pszVolume, ULARGE_INTEGER *pqwFreeCaller, ULARGE_INTEGER *pqwTot, ULARGE_INTEGER *pqwFree);
const TCHAR * const g_szWindowClassName = TEXT("MSIE4.0 Webvw.DLL ThumbCtl");
STDAPI IsSafePage(IUnknown *punkSite)
{
// Return S_FALSE if we don't have a host site since we have no way of doing a
// security check. This is as far as VB 5.0 apps get.
if (!punkSite)
return S_FALSE;
HRESULT hr = E_ACCESSDENIED;
WCHAR wszPath[MAX_PATH];
wszPath[0] = 0;
// ask the browser, for example we are in a .HTM doc
IBrowserService* pbs;
if (SUCCEEDED(IUnknown_QueryService(punkSite, SID_SShellBrowser,
IID_PPV_ARG(IBrowserService, &pbs))))
{
LPITEMIDLIST pidl;
if (SUCCEEDED(pbs->GetPidl(&pidl)))
{
DWORD dwAttribs = SFGAO_FOLDER;
if (SUCCEEDED(SHGetNameAndFlagsW(pidl, SHGDN_FORPARSING, wszPath,
ARRAYSIZE(wszPath), &dwAttribs))
&& (dwAttribs & SFGAO_FOLDER)) // This is a folder. So, wszPath should be the path for it's webview template
{
// find the template path from webview, for example a .HTT file
IOleCommandTarget *pct;
if (SUCCEEDED(IUnknown_QueryService(punkSite, SID_DefView,
IID_PPV_ARG(IOleCommandTarget, &pct))))
{
VARIANT vPath;
vPath.vt = VT_EMPTY;
if (pct->Exec(&CGID_DefView, DVCMDID_GETTEMPLATEDIRNAME, 0
, NULL, &vPath) == S_OK)
{
if (vPath.vt == VT_BSTR && vPath.bstrVal)
{
DWORD cchPath = ARRAYSIZE(wszPath);
if (S_OK != PathCreateFromUrlW(vPath.bstrVal,
wszPath, &cchPath, 0))
{
// it might not be an URL, in this case it is a file path
StrCpyNW(wszPath, vPath.bstrVal, ARRAYSIZE(wszPath));
}
}
VariantClear(&vPath);
}
pct->Release();
}
}
ILFree(pidl);
}
pbs->Release();
}
else
{
ASSERT(0); // no browser, where are we?
}
if (wszPath[0])
hr = SHRegisterValidateTemplate(wszPath, SHRVT_VALIDATE | SHRVT_PROMPTUSER | SHRVT_REGISTERIFPROMPTOK);
return hr;
}
// === INTERFACE ===
// *** IThumbCtl ***
STDMETHODIMP CThumbCtl::displayFile(BSTR bsFileName, VARIANT_BOOL *pfSuccess)
{
ASSERT(pfSuccess != NULL);
HRESULT hr = E_FAIL;
*pfSuccess = VARIANT_FALSE;
if ((S_OK != LocalZoneCheck(m_spClientSite)) && (S_OK != IsSafePage(m_spClientSite)))
{
// We don't trust this host, so we are going to not carry
// out the action. We are going to return E_ACCESSDENIED so they can't
// determine if the path exists or not.
// due to rajeshg's request we return S_FALSE
// this is because webvw has a customization feature letting people choose
// a intranet htt file as their folder.htt, but for security we generally need
// to block random intranet web pages from calling this method. This will break
// a case where the customization is done on a NT machine, but the user tries to
// view it using Millennium, it will not show any image and pop up error messages
// if we return E_ACCESSDENIED.
hr = S_FALSE;
}
else
{
// Cancel pending bitmap request if in thumbnail mode && have a functioning IThumbnail
// && haven't yet received our bitmap
if(!m_fRootDrive && m_fHaveIThumbnail && m_hbm == NULL)
{
m_pthumb->GetBitmap(NULL, 0, 0, 0);
}
// change ID to catch late bitmap computed
++m_dwThumbnailID;
// if already displaying something, refresh
if(m_fRootDrive || m_hbm)
{
if(m_hbm)
{
DeleteObject(m_hbm);
m_hbm = NULL;
}
FireViewChange();
}
// Now work on new thumbnail
m_fRootDrive = FALSE;
// check for non-empty file name
if(bsFileName && bsFileName[0])
{
TCHAR szFileName[INTERNET_MAX_URL_LENGTH];
SHUnicodeToTChar(bsFileName, szFileName, ARRAYSIZE(szFileName));
DWORD dwAttrs = GetFileAttributes(szFileName);
// Pie Chart
if(PathIsRoot(szFileName))
{
if(SUCCEEDED(ComputeFreeSpace(szFileName)))
{
m_fRootDrive = TRUE;
*pfSuccess = VARIANT_TRUE;
}
}
// Thumbnail
else if(!(dwAttrs & FILE_ATTRIBUTE_DIRECTORY) && !PathIsSlow(szFileName, dwAttrs)) // should really be calling this from Shell32 private functions
{
if(!m_fInitThumb)
{
m_fHaveIThumbnail = SUCCEEDED(SetupIThumbnail());
m_fInitThumb = TRUE;
}
if(m_fHaveIThumbnail)
{
SIZE size;
AtlHiMetricToPixel(&m_sizeExtent, &size);
if(EVAL(size.cx > 0 && size.cy > 0))
{
if(SUCCEEDED(m_pthumb->GetBitmap(bsFileName, m_dwThumbnailID, size.cx, size.cy)))
{
*pfSuccess = VARIANT_TRUE;
}
}
}
}
}
hr = S_OK;
}
return hr;
} // displayFile
STDMETHODIMP CThumbCtl::haveThumbnail(VARIANT_BOOL *pfRes)
{
HRESULT hr;
*pfRes = VARIANT_FALSE;
if ((S_OK != LocalZoneCheck(m_spClientSite)) && (S_OK != IsSafePage(m_spClientSite)))
{
// We don't trust this host, so we are going to not carry
// out the action. We are going to return E_ACCESSDENIED so they can't
// determine if the path exists or not.
// due to rajeshg's request we return S_FALSE
// this is because webvw has a customization feature letting people choose
// a intranet htt file as their folder.htt, but for security we generally need
// to block random intranet web pages from calling this method. This will break
// a case where the customization is done on a NT machine, but the user tries to
// view it using Millennium, it will not show any image and pop up error messages
// if we return E_ACCESSDENIED.
hr = S_FALSE;
}
else
{
*pfRes = (m_fRootDrive || m_hbm) ? VARIANT_TRUE : VARIANT_FALSE;
hr = S_OK;
}
return hr;
}
STDMETHODIMP CThumbCtl::get_freeSpace(BSTR *pbs)
{
HRESULT hr;
if ((S_OK != LocalZoneCheck(m_spClientSite)) && (S_OK != IsSafePage(m_spClientSite)))
{
// We don't trust this host, so we are going to not carry
// out the action. We are going to return E_ACCESSDENIED so they can't
// determine if the path exists or not.
*pbs = SysAllocString(L"");
hr = S_FALSE;
}
else
{
get_GeneralSpace(m_dwlFreeSpace, pbs);
hr = S_OK;
}
return hr;
} // get_freeSpace
STDMETHODIMP CThumbCtl::get_usedSpace(BSTR *pbs)
{
HRESULT hr;
if ((S_OK != LocalZoneCheck(m_spClientSite)) && (S_OK != IsSafePage(m_spClientSite)))
{
// We don't trust this host, so we are going to not carry
// out the action. We are going to return E_ACCESSDENIED so they can't
// determine if the path exists or not.
*pbs = SysAllocString(L"");
hr = S_FALSE;
}
else
{
get_GeneralSpace(m_dwlUsedSpace, pbs);
hr = S_OK;
}
return hr;
} // get_usedSpace
STDMETHODIMP CThumbCtl::get_totalSpace(BSTR *pbs)
{
HRESULT hr;
if ((S_OK != LocalZoneCheck(m_spClientSite)) && (S_OK != IsSafePage(m_spClientSite)))
{
// We don't trust this host, so we are going to not carry
// out the action. We are going to return E_ACCESSDENIED so they can't
// determine if the path exists or not.
*pbs = SysAllocString(L"");
hr = S_FALSE;
}
else
{
get_GeneralSpace(m_dwlTotalSpace, pbs);
hr = S_OK;
}
return hr;
} // get_totalSpace
// *** IObjectSafety ***
STDMETHODIMP CThumbCtl::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions,
DWORD *pdwEnabledOptions)
{
ATLTRACE(_T("IObjectSafetyImpl::GetInterfaceSafetyOptions\n"));
if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL)
return E_POINTER;
HRESULT hr = S_OK;
if (riid == IID_IDispatch)
{
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER & INTERFACESAFE_FOR_UNTRUSTED_DATA;
*pdwEnabledOptions = m_dwCurrentSafety & INTERFACESAFE_FOR_UNTRUSTED_CALLER & INTERFACESAFE_FOR_UNTRUSTED_DATA;
}
else
{
*pdwSupportedOptions = 0;
*pdwEnabledOptions = 0;
hr = E_NOINTERFACE;
}
return hr;
}
// *** ISupportsErrorInfo ***
STDMETHODIMP CThumbCtl::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IThumbCtl,
};
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
// *** IViewObjectEx ***
STDMETHODIMP CThumbCtl::GetViewStatus(DWORD* pdwStatus)
{
ATLTRACE(_T("IViewObjectExImpl::GetViewStatus\n"));
*pdwStatus = VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE;
return S_OK;
}
// *** IOleInPlaceActiveObject ***
HRESULT CThumbCtl::TranslateAccelerator(LPMSG pMsg)
{
HRESULT hres = S_OK;
if (!m_fTabRecieved)
{
hres = IOleInPlaceActiveObjectImpl<CThumbCtl>::TranslateAccelerator(pMsg);
// If we did not handle this and if it is a tab (and we are not getting it in a cycle), forward it to trident, if present.
if (hres != S_OK && pMsg && (pMsg->wParam == VK_TAB || pMsg->wParam == VK_F6) && m_spClientSite)
{
if (GetFocus() != m_hwnd)
{
::SetFocus(m_hwnd);
hres = S_OK;
}
else
{
IOleControlSite* pocs = NULL;
if (SUCCEEDED(m_spClientSite->QueryInterface(IID_IOleControlSite, (void **)&pocs)))
{
DWORD grfModifiers = 0;
if (GetKeyState(VK_SHIFT) & 0x8000)
{
grfModifiers |= 0x1; //KEYMOD_SHIFT
}
if (GetKeyState(VK_CONTROL) & 0x8000)
{
grfModifiers |= 0x2; //KEYMOD_CONTROL;
}
if (GetKeyState(VK_MENU) & 0x8000)
{
grfModifiers |= 0x4; //KEYMOD_ALT;
}
m_fTabRecieved = TRUE;
hres = pocs->TranslateAccelerator(pMsg, grfModifiers);
m_fTabRecieved = FALSE;
}
}
}
}
return hres;
}
// === PUBLIC FUNCTIONS ===
// CONSTRUCTOR/DESTRUCTOR
CThumbCtl::CThumbCtl(void):
m_fRootDrive(FALSE),
m_fInitThumb(FALSE),
m_fHaveIThumbnail(FALSE),
m_pthumb(NULL),
m_hwnd(NULL),
m_hbm(NULL),
m_dwThumbnailID(0),
m_dwlFreeSpace(0),
m_dwlUsedSpace(0),
m_dwlTotalSpace(0),
m_dwUsedSpacePer1000(0),
m_fUseSystemColors(TRUE)
{
m_fTabRecieved = FALSE;
}
CThumbCtl::~CThumbCtl(void)
{
if(m_hbm)
{
DeleteObject(m_hbm);
m_hbm = NULL;
}
if(m_pthumb)
{
m_pthumb->Release(); // will cancel pending bitmap requests
m_pthumb = NULL;
}
if(m_hwnd)
{
EVAL(::DestroyWindow(m_hwnd));
m_hwnd = NULL;
}
}
// === PRIVATE FUNCTIONS ===
// Thumbnail drawing functions
HRESULT CThumbCtl::SetupIThumbnail(void)
{
HRESULT hr = E_FAIL;
// Create Window Class
WNDCLASS wc;
if (!::GetClassInfoWrap(_Module.GetModuleInstance(), g_szWindowClassName, &wc))
{
wc.style = 0;
wc.lpfnWndProc = CThumbCtl::WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = _Module.GetModuleInstance();
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szWindowClassName;
RegisterClass(&wc);
}
m_hwnd = CreateWindow(g_szWindowClassName, NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, _Module.GetModuleInstance(), this);
if(m_hwnd)
{
if(SUCCEEDED(CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER, IID_IThumbnail, (void **)&m_pthumb)))
{
if(SUCCEEDED(m_pthumb->Init(m_hwnd, WM_HTML_BITMAP)))
{
hr = S_OK;
}
}
if(FAILED(hr))
{
EVAL(::DestroyWindow(m_hwnd));
m_hwnd = NULL;
}
}
return hr;
}
LRESULT CALLBACK CThumbCtl::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CThumbCtl *ptc = (CThumbCtl *)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch(uMsg)
{
case WM_CREATE:
{
ptc = (CThumbCtl *)((CREATESTRUCT *)lParam)->lpCreateParams;
::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)ptc);
}
break;
case WM_HTML_BITMAP:
// check that ptc is still alive, bitmap is current using ID
if(ptc && ptc->m_dwThumbnailID == wParam)
{
// ptc->displayFile() should've destroyed old bitmap already, but doesn't hurt to check.
if(!EVAL(ptc->m_hbm == NULL))
{
DeleteObject(ptc->m_hbm);
}
ptc->m_hbm = (HBITMAP)lParam;
ptc->InvokeOnThumbnailReady();
}
else if(lParam)
{
DeleteObject((HBITMAP)lParam);
}
break;
case WM_DESTROY:
// ignore late messages
if(ptc)
{
MSG msg;
while(PeekMessage(&msg, hWnd, WM_HTML_BITMAP, WM_HTML_BITMAP, PM_REMOVE))
{
if(msg.lParam)
{
DeleteObject((HBITMAP)msg.lParam);
}
}
::SetWindowLongPtr(hWnd, GWLP_USERDATA, NULL);
}
break;
default:
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
// Pie Chart functions
HRESULT CThumbCtl::ComputeFreeSpace(LPTSTR pszFileName)
{
ULARGE_INTEGER qwFreeCaller; // use this for free space -- this will take into account disk quotas and such on NT
ULARGE_INTEGER qwTotal;
ULARGE_INTEGER qwFree; // unused
static PFNSHGETDISKFREESPACE pfnSHGetDiskFreeSpace = NULL;
if (NULL == pfnSHGetDiskFreeSpace)
{
HINSTANCE hinstShell32 = LoadLibrary(TEXT("SHELL32.DLL"));
if (hinstShell32)
{
#ifdef UNICODE
pfnSHGetDiskFreeSpace = (PFNSHGETDISKFREESPACE)GetProcAddress(hinstShell32, "SHGetDiskFreeSpaceExW");
#else
pfnSHGetDiskFreeSpace = (PFNSHGETDISKFREESPACE)GetProcAddress(hinstShell32, "SHGetDiskFreeSpaceExA");
#endif
}
}
// Compute free & total space and check for valid results
// if have a fn pointer call SHGetDiskFreeSpaceA
if( pfnSHGetDiskFreeSpace
&& pfnSHGetDiskFreeSpace(pszFileName, &qwFreeCaller, &qwTotal, &qwFree) )
{
m_dwlFreeSpace = qwFreeCaller.QuadPart;
m_dwlTotalSpace = qwTotal.QuadPart;
m_dwlUsedSpace = m_dwlTotalSpace - m_dwlFreeSpace;
if ((m_dwlTotalSpace > 0) && (m_dwlFreeSpace <= m_dwlTotalSpace))
{
// some special cases require interesting treatment
if(m_dwlTotalSpace == 0 || m_dwlFreeSpace == m_dwlTotalSpace)
{
m_dwUsedSpacePer1000 = 0;
}
else if(m_dwlFreeSpace == 0)
{
m_dwUsedSpacePer1000 = 1000;
}
else
{
// not completely full or empty
m_dwUsedSpacePer1000 = (DWORD)(m_dwlUsedSpace * 1000 / m_dwlTotalSpace);
// Trick: if user has extremely little free space, the user expects to still see
// a tiny free slice -- not a full drive. Similarly for almost free drive.
if(m_dwUsedSpacePer1000 == 0)
{
m_dwUsedSpacePer1000 = 1;
}
else if(m_dwUsedSpacePer1000 == 1000)
{
m_dwUsedSpacePer1000 = 999;
}
}
return S_OK;
}
}
return E_FAIL;
}
// 32 should be plenty
#define STRLENGTH_SPACE 32
HRESULT CThumbCtl::get_GeneralSpace(DWORDLONG dwlSpace, BSTR *pbs)
{
ASSERT(pbs != NULL);
WCHAR wszText[STRLENGTH_SPACE];
if(m_fRootDrive)
{
StrFormatByteSizeW(dwlSpace, wszText, ARRAYSIZE(wszText));
*pbs = SysAllocString(wszText);
}
else
{
*pbs = SysAllocString(L"");
}
return *pbs? S_OK: E_OUTOFMEMORY;
}
HRESULT CThumbCtl::Draw3dPie(HDC hdc, LPRECT lprc, DWORD dwPer1000, const COLORREF *lpColors)
{
ASSERT(lprc != NULL && lpColors != NULL);
enum
{
COLOR_UP = 0,
COLOR_DN,
COLOR_UPSHADOW,
COLOR_DNSHADOW,
COLOR_NUM // #of entries
};
// The majority of this code came from "drawpie.c"
const LONG c_lShadowScale = 6; // ratio of shadow depth to height
const LONG c_lAspectRatio = 2; // ratio of width : height of ellipse
// We make sure that the aspect ratio of the pie-chart is always preserved
// regardless of the shape of the given rectangle
// Stabilize the aspect ratio now...
LONG lHeight = lprc->bottom - lprc->top;
LONG lWidth = lprc->right - lprc->left;
LONG lTargetHeight = (lHeight * c_lAspectRatio <= lWidth? lHeight: lWidth / c_lAspectRatio);
LONG lTargetWidth = lTargetHeight * c_lAspectRatio; // need to adjust because w/c * c isn't always == w
// Shrink the rectangle on both sides to the correct size
lprc->top += (lHeight - lTargetHeight) / 2;
lprc->bottom = lprc->top + lTargetHeight;
lprc->left += (lWidth - lTargetWidth) / 2;
lprc->right = lprc->left + lTargetWidth;
// Compute a shadow depth based on height of the image
LONG lShadowDepth = lTargetHeight / c_lShadowScale;
// check dwPer1000 to ensure within bounds
if(dwPer1000 > 1000)
dwPer1000 = 1000;
// Now the drawing function
int cx, cy, rx, ry, x, y;
int uQPctX10;
RECT rcItem;
HRGN hEllRect, hEllipticRgn, hRectRgn;
HBRUSH hBrush, hOldBrush;
HPEN hPen, hOldPen;
rcItem = *lprc;
rcItem.left = lprc->left;
rcItem.top = lprc->top;
rcItem.right = lprc->right - rcItem.left;
rcItem.bottom = lprc->bottom - rcItem.top - lShadowDepth;
rx = rcItem.right / 2;
cx = rcItem.left + rx - 1;
ry = rcItem.bottom / 2;
cy = rcItem.top + ry - 1;
if (rx<=10 || ry<=10)
{
return S_FALSE;
}
rcItem.right = rcItem.left+2*rx;
rcItem.bottom = rcItem.top+2*ry;
/* Translate to first quadrant of a Cartesian system
*/
uQPctX10 = (dwPer1000 % 500) - 250;
if (uQPctX10 < 0)
{
uQPctX10 = -uQPctX10;
}
/* Calc x and y. I am trying to make the area be the right percentage.
** I don't know how to calculate the area of a pie slice exactly, so I
** approximate it by using the triangle area instead.
*/
// NOTE-- *** in response to the above comment ***
// Calculating the area of a pie slice exactly is actually very
// easy by conceptually rescaling into a circle but the complications
// introduced by having to work in fixed-point arithmetic makes it
// unworthwhile to code this-- CemP
if (uQPctX10 < 120)
{
x = IntSqrt(((DWORD)rx*(DWORD)rx*(DWORD)uQPctX10*(DWORD)uQPctX10)
/((DWORD)uQPctX10*(DWORD)uQPctX10+(250L-(DWORD)uQPctX10)*(250L-(DWORD)uQPctX10)));
y = IntSqrt(((DWORD)rx*(DWORD)rx-(DWORD)x*(DWORD)x)*(DWORD)ry*(DWORD)ry/((DWORD)rx*(DWORD)rx));
}
else
{
y = IntSqrt((DWORD)ry*(DWORD)ry*(250L-(DWORD)uQPctX10)*(250L-(DWORD)uQPctX10)
/((DWORD)uQPctX10*(DWORD)uQPctX10+(250L-(DWORD)uQPctX10)*(250L-(DWORD)uQPctX10)));
x = IntSqrt(((DWORD)ry*(DWORD)ry-(DWORD)y*(DWORD)y)*(DWORD)rx*(DWORD)rx/((DWORD)ry*(DWORD)ry));
}
/* Switch on the actual quadrant
*/
switch (dwPer1000 / 250)
{
case 1:
y = -y;
break;
case 2:
break;
case 3:
x = -x;
break;
default: // case 0 and case 4
x = -x;
y = -y;
break;
}
/* Now adjust for the center.
*/
x += cx;
y += cy;
// Hack to get around bug in NTGDI
x = x < 0 ? 0 : x;
/* Draw the shadows using regions (to reduce flicker).
*/
hEllipticRgn = CreateEllipticRgnIndirect(&rcItem);
OffsetRgn(hEllipticRgn, 0, lShadowDepth);
hEllRect = CreateRectRgn(rcItem.left, cy, rcItem.right, cy+lShadowDepth);
hRectRgn = CreateRectRgn(0, 0, 0, 0);
CombineRgn(hRectRgn, hEllipticRgn, hEllRect, RGN_OR);
OffsetRgn(hEllipticRgn, 0, -(int)lShadowDepth);
CombineRgn(hEllRect, hRectRgn, hEllipticRgn, RGN_DIFF);
/* Always draw the whole area in the free shadow/
*/
hBrush = CreateSolidBrush(lpColors[COLOR_DNSHADOW]);
if (hBrush)
{
FillRgn(hdc, hEllRect, hBrush);
DeleteObject(hBrush);
}
/* Draw the used shadow only if the disk is at least half used.
*/
if (dwPer1000>500 && (hBrush = CreateSolidBrush(lpColors[COLOR_UPSHADOW]))!=NULL)
{
DeleteObject(hRectRgn);
hRectRgn = CreateRectRgn(x, cy, rcItem.right, lprc->bottom);
CombineRgn(hEllipticRgn, hEllRect, hRectRgn, RGN_AND);
FillRgn(hdc, hEllipticRgn, hBrush);
DeleteObject(hBrush);
}
DeleteObject(hRectRgn);
DeleteObject(hEllipticRgn);
DeleteObject(hEllRect);
hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
hOldPen = (HPEN__*) SelectObject(hdc, hPen);
// if per1000 is 0 or 1000, draw full elipse, otherwise, also draw a pie section.
// we might have a situation where per1000 isn't 0 or 1000 but y == cy due to approx error,
// so make sure to draw the ellipse the correct color, and draw a line (with Pie()) to
// indicate not completely full or empty pie.
hBrush = CreateSolidBrush(lpColors[dwPer1000 < 500 && y == cy && x < cx? COLOR_DN: COLOR_UP]);
hOldBrush = (HBRUSH__*) SelectObject(hdc, hBrush);
Ellipse(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
SelectObject(hdc, hOldBrush);
DeleteObject(hBrush);
if(dwPer1000 != 0 && dwPer1000 != 1000)
{
// display small sub-section of ellipse for smaller part
hBrush = CreateSolidBrush(lpColors[COLOR_DN]);
hOldBrush = (HBRUSH__*) SelectObject(hdc, hBrush);
// NTRAID#087993-2000/02/16-aidanl: Pie may malfunction when y approaches cy
// If y == cy (when the disk is almost full)and if x approaches
// rcItem.left, on win9x, Pie malfunctions. It draws the larger portion
// of the pie, instead of the smaller portion. We work around it by
// adding 1 to y.
Pie(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
rcItem.left, cy, x, (y == cy) ? (y + 1) : y);
SelectObject(hdc, hOldBrush);
DeleteObject(hBrush);
}
Arc(hdc, rcItem.left, rcItem.top+lShadowDepth, rcItem.right - 1, rcItem.bottom+lShadowDepth - 1,
rcItem.left, cy+lShadowDepth, rcItem.right, cy+lShadowDepth-1);
MoveToEx(hdc, rcItem.left, cy, NULL);
LineTo(hdc, rcItem.left, cy+lShadowDepth);
MoveToEx(hdc, rcItem.right-1, cy, NULL);
LineTo(hdc, rcItem.right-1, cy+lShadowDepth);
if(dwPer1000 > 500 && dwPer1000 < 1000)
{
MoveToEx(hdc, x, y, NULL);
LineTo(hdc, x, y+lShadowDepth);
}
SelectObject(hdc, hOldPen);
DeleteObject(hPen);
return S_OK; // Everything worked fine
} // Draw3dPie
DWORD CThumbCtl::IntSqrt(DWORD dwNum)
{
// This code came from "drawpie.c"
DWORD dwSqrt = 0;
DWORD dwRemain = 0;
DWORD dwTry = 0;
for(int i=0; i<16; ++i) {
dwRemain = (dwRemain<<2) | (dwNum>>30);
dwSqrt <<= 1;
dwTry = dwSqrt*2 + 1;
if (dwRemain >= dwTry) {
dwRemain -= dwTry;
dwSqrt |= 0x01;
}
dwNum <<= 2;
}
return dwSqrt;
} // IntSqrt
// General functions
void CThumbCtl::InvokeOnThumbnailReady(void)
{
// Fire off "OnThumbnailReady" event to our connection points to indicate that
// either a thumbnail has been computed or we have no thumbnail for this file.
DISPPARAMS dp = {0, NULL, 0, NULL}; // no parameters
IUnknown **pp = NULL; // traverses connection points, where it is interpreted as IDispatch*
Lock();
for(pp = m_vec.begin(); pp < m_vec.end(); ++pp)
{
if(pp)
{
((IDispatch *)*pp)->Invoke(DISPID_ONTHUMBNAILREADY, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &dp, NULL, NULL, NULL);
}
}
Unlock();
FireViewChange();
}
HRESULT CThumbCtl::OnDraw(ATL_DRAWINFO& di)
{
HDC hdc = di.hdcDraw;
RECT rc = *(LPRECT)di.prcBounds;
HRESULT hr = S_OK;
if(m_fRootDrive || m_hbm)
{
HPALETTE hpal = NULL;
// Create pallete appropriate for this HDC
if(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
{
hpal = SHCreateShellPalette(hdc);
HPALETTE hpalOld = SelectPalette(hdc, hpal, TRUE);
RealizePalette(hdc);
// Old one needs to be selected back in
SelectPalette(hdc, hpalOld, TRUE);
}
if(m_fRootDrive)
{
// Draw a pie chart
if(m_fUseSystemColors)
{
// system colors can change!
m_acrChartColors[PIE_USEDCOLOR] = GetSysColor(COLOR_3DFACE);
m_acrChartColors[PIE_FREECOLOR] = GetSysColor(COLOR_3DHILIGHT);
m_acrChartColors[PIE_USEDSHADOW] = GetSysColor(COLOR_3DSHADOW);
m_acrChartColors[PIE_FREESHADOW] = GetSysColor(COLOR_3DFACE);
}
else if(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
{
// Call GetNearestColor on the colors to make sure they're on the palette
// Of course, system colors ARE on the palette (I think)
DWORD dw = 0; // index
for(dw = 0; dw < PIE_NUM; dw++)
{
m_acrChartColors[dw] = GetNearestColor(hdc, m_acrChartColors[dw]);
}
}
hr = Draw3dPie(hdc, &rc, m_dwUsedSpacePer1000, m_acrChartColors);
}
else
{
// Draw the Thumbnail bitmap
HDC hdcBitmap = CreateCompatibleDC(hdc);
if (hdcBitmap)
{
BITMAP bm;
SelectObject(hdcBitmap, m_hbm);
GetObject(m_hbm, SIZEOF(bm), &bm);
if(bm.bmWidth == rc.right - rc.left && bm.bmHeight == rc.bottom - rc.top)
{
BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
hdcBitmap, 0, 0, SRCCOPY);
}
else
{
SetStretchBltMode(hdc, COLORONCOLOR);
StretchBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
hdcBitmap, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
}
DeleteDC(hdcBitmap);
}
}
// clean up DC, palette
if(hpal)
{
DeleteObject(hpal);
}
}
else
{
SelectObject(hdc, GetStockObject(WHITE_PEN));
SelectObject(hdc, GetStockObject(WHITE_BRUSH));
// Just draw a blank rectangle
Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
}
return hr;
}