// fldricon.cpp : Implementation of CWebViewFolderIcon #include "priv.h" #include #include #include #include #include #include #include #include #include #include #include #include // for IEParseDisplayNameW() & IEGetNameAndFlags() #include #include #define UNINITIALIZE_BOOL 5 const CLSID CLSID_WebViewFolderIconOld = {0xe5df9d10,0x3b52,0x11d1,{0x83,0xe8,0x00,0xa0,0xc9,0x0d,0xc8,0x49}}; // retired from service, so made private // PERF: Shell allocator, inserted here because SHRealloc // isn't imported into webvw, this module's hosting executable. // If we get SHRealloc, the following block can be removed: #define _EXPL_SHELL_ALLOCATOR_ #ifdef _EXPL_SHELL_ALLOCATOR_ #define SHRealloc(pv, cb) shrealloc(pv, cb) void* shrealloc(void* pv, size_t cb) { void *pvRet = NULL; IMalloc* pMalloc; if (SUCCEEDED(SHGetMalloc(&pMalloc))) { pvRet = pMalloc->Realloc(pv, cb); pMalloc->Release(); } return pvRet; } #endif _EXPL_SHELL_ALLOCATOR_ // For registering the window class const TCHAR * const g_szWindowClassName = TEXT("WebViewFolderIcon view messaging"); DWORD 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; } // Make sure you don't begin a drag with random clicking BOOL CheckForDragBegin(HWND hwnd, int x, int y) { RECT rc; int dxClickRect = GetSystemMetrics(SM_CXDRAG); int dyClickRect = GetSystemMetrics(SM_CYDRAG); ASSERT((dxClickRect > 1) && (dyClickRect > 1)); // See if the user moves a certain number of pixels in any direction SetRect(&rc, x - dxClickRect, y - dyClickRect, x + dxClickRect, y + dyClickRect); MapWindowRect(hwnd, NULL, &rc); SetCapture(hwnd); do { MSG msg; if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // See if the application wants to process the message... if (CallMsgFilter(&msg, MSGF_COMMCTRL_BEGINDRAG) != 0) continue; switch (msg.message) { case WM_LBUTTONUP: case WM_RBUTTONUP: PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam); ReleaseCapture(); return FALSE; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: ReleaseCapture(); return FALSE; case WM_MOUSEMOVE: if (!PtInRect(&rc, msg.pt)) { ReleaseCapture(); return TRUE; } break; default: if (GetCapture() != hwnd) ReleaseCapture(); TranslateMessage(&msg); DispatchMessage(&msg); break; } } else WaitMessage(); /* Don't chew 100% CPU */ // WM_CANCELMODE messages will unset the capture, in that // case I want to exit this loop } while (GetCapture() == hwnd); return FALSE; } /////////////////////////////////// // // CWebViewFolderIcon functions // /////////////////////////////////// CWebViewFolderIcon::CWebViewFolderIcon() : m_pccpDV(NULL), m_hIcon(0), m_iIconIndex(-1), m_hbm(NULL), m_pthumb(NULL), m_pidl(NULL), m_msgHwnd(NULL), m_pdispWindow(NULL), m_dwThumbnailID(0), m_bHilite(FALSE) { m_percentScale = 100; m_lImageWidth = 0; m_lImageHeight = 0; m_sizLabel.cx = m_sizLabel.cy = 0; m_pszDisplayName = NULL; m_bHasRect = FALSE; m_ViewUser = VIEW_LARGEICON; m_ViewCurrent = VIEW_LARGEICON; m_clickStyle = 2; // Default is double-click m_fUseSystemColors = TRUE; m_bAdvPropsOn = VARIANT_TRUE; m_bRegWndClass = FALSE; m_ullFreeSpace = 0; m_ullUsedSpace = 0; m_ullTotalSpace = 0; m_highestIndexSlice = 0; m_fTabRecieved = FALSE; m_pcm3 = NULL; m_pDropTargetCache = NULL; m_fIsHostWebView = UNINITIALIZE_BOOL; m_hdc = NULL; m_fRectAdjusted = 0; m_hbmDrag = NULL; m_hdsaSlices = DSA_Create(sizeof(PieSlice_S), SLICE_NUM_GROW); /* * Listview puts a SM_CXEDGE between the icon and the label, * so we will default to that value. (Clients can adjust with * labelGap property.) */ m_cxLabelGap = GetSystemMetrics(SM_CXEDGE); m_pfont = NULL; m_hfAmbient = NULL; } CWebViewFolderIcon::~CWebViewFolderIcon() { _ClearLabel(); _ClearAmbientFont(); if (m_hIcon) { DestroyIcon(m_hIcon); m_hIcon = NULL; } if (m_hdc) { DeleteDC(m_hdc); m_hdc = NULL; } if (m_hbmDrag) { DeleteObject(m_hbmDrag); m_hbmDrag = NULL; } ILFree(m_pidl); if (m_hbm) { DeleteObject(m_hbm); m_hbm = NULL; } if (m_hfAmbient) { DeleteObject(m_hfAmbient); m_hfAmbient = NULL; } ATOMICRELEASE(m_pDropTargetCache); ATOMICRELEASE(m_pthumb); DSA_Destroy(m_hdsaSlices); if (m_msgHwnd) ::DestroyWindow(m_msgHwnd); if (m_bRegWndClass) { UnregisterClass(g_szWindowClassName, _Module.GetModuleInstance()); } } HRESULT CWebViewFolderIcon::_SetupWindow(void) { // On the first time register the messaging window if (!m_bRegWndClass) { // Create Window Class for messaging m_msgWc.style = 0; m_msgWc.lpfnWndProc = CWebViewFolderIcon::WndProc; m_msgWc.cbClsExtra = 0; m_msgWc.cbWndExtra = 0; m_msgWc.hInstance = _Module.GetModuleInstance(); m_msgWc.hIcon = NULL; m_msgWc.hCursor = NULL; m_msgWc.hbrBackground = NULL; m_msgWc.lpszMenuName = NULL; m_msgWc.lpszClassName = g_szWindowClassName; m_bRegWndClass = RegisterClass(&m_msgWc); } if (!m_msgHwnd) { m_msgHwnd = CreateWindow(g_szWindowClassName, NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, _Module.GetModuleInstance(), this); } return m_msgHwnd ? S_OK : E_FAIL; } // Must be called before using the IThumbnail. Also sets up the thumbnail message window HRESULT CWebViewFolderIcon::SetupIThumbnail(void) { HRESULT hr = _SetupWindow(); if (SUCCEEDED(hr)) { if (m_pthumb) hr = S_OK; else { hr = CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThumbnail2, &m_pthumb)); if (SUCCEEDED(hr)) hr = m_pthumb->Init(m_msgHwnd, WM_HTML_BITMAP); } } return hr; } // General functions HRESULT CWebViewFolderIcon::_InvokeOnThumbnailReady() { // 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 //Lock(); for (IUnknown** pp = m_vec.begin(); pp < m_vec.end(); pp++) { if (pp) { IDispatch* pDispatch = SAFECAST(*pp, IDispatch*); pDispatch->Invoke(DISPID_WEBVIEWFOLDERICON_ONTHUMBNAILREADY, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dp, NULL, NULL, NULL); } } //Unlock(); FireViewChange(); return S_OK; } // The S_FALSE return value indicates that this function has succeeded, but the out pidl is still NULL HRESULT CWebViewFolderIcon::_GetFullPidl(LPITEMIDLIST *ppidl) { *ppidl = NULL; HRESULT hr; if (m_pidl) { hr = SHILClone(m_pidl, ppidl); // dupe our copy } else { // This used to be an EVAL, but it can legitimately fail if the script did not // specify a valid path // This will fail if we are hosted in a web page instead of the HTML WebView frame in DefView. IUnknown *punk; hr = IUnknown_QueryService(m_spClientSite, SID_SFolderView, IID_PPV_ARG(IUnknown, &punk)); if (SUCCEEDED(hr)) { if (S_OK == SHGetIDListFromUnk(punk, ppidl)) { Pidl_Set(&m_pidl, *ppidl); // cache a copy of this } punk->Release(); } } return hr; } HRESULT _GetPidlAndShellFolderFromPidl(LPITEMIDLIST pidl, LPITEMIDLIST *ppidlLast, IShellFolder** ppsfParent) { LPCITEMIDLIST pidlLast; HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, ppsfParent), &pidlLast); if (SUCCEEDED(hr)) { *ppidlLast = ILClone(pidlLast); } return hr; } // RETURN VALUES: // SUCCEEDED() means *ppidlLast and/or *ppsfParent can be NULL. // FAILED() means a *ppidlLast *ppsfParent are going to be returned NULL. HRESULT CWebViewFolderIcon::_GetPidlAndShellFolder(LPITEMIDLIST *ppidlLast, IShellFolder** ppsfParent) { LPITEMIDLIST pidl; HRESULT hr = _GetFullPidl(&pidl); if (hr == S_OK) { hr = _GetPidlAndShellFolderFromPidl(pidl, ppidlLast, ppsfParent); ILFree(pidl); } else { *ppidlLast = NULL; *ppsfParent = NULL; } return hr; } // Get Trident's HWND HRESULT CWebViewFolderIcon::_GetHwnd(HWND* phwnd) { HRESULT hr; if (m_spInPlaceSite) { hr = m_spInPlaceSite->GetWindow(phwnd); } else { IOleInPlaceSiteWindowless * poipsw; hr = m_spClientSite->QueryInterface(IID_PPV_ARG(IOleInPlaceSiteWindowless, &poipsw)); if (EVAL(SUCCEEDED(hr))) { hr = poipsw->GetWindow(phwnd); poipsw->Release(); } } return hr; } HRESULT CWebViewFolderIcon::_GetChildUIObjectOf(REFIID riid, void **ppvObj) { LPITEMIDLIST pidlLast; IShellFolder *psfParent; HRESULT hr = _GetPidlAndShellFolder(&pidlLast, &psfParent); if (hr == S_OK) { HWND hwnd; _GetHwnd(&hwnd); hr = psfParent->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST *)&pidlLast, riid, NULL, ppvObj); psfParent->Release(); ILFree(pidlLast); } else hr = E_FAIL; return hr; } // Center point of focus rectangle HRESULT CWebViewFolderIcon::_GetCenterPoint(POINT *pt) { pt->y = ((m_rcPos.top + m_rcPos.bottom)/2); pt->x = ((m_rcPos.left + m_rcPos.right)/2); return S_OK; } HRESULT CWebViewFolderIcon::_IsSafe() { HRESULT hr; if (0==m_dwCurrentSafety) { hr = S_OK; } else { if (_IsPubWizHosted()) hr = S_OK; else hr = IsSafePage(m_spClientSite); } return hr; } BOOL CWebViewFolderIcon::IsSafeToDefaultVerb(void) { return S_OK == _IsSafe(); } // If the focus rectangle is not in the specified RectState (on or off) change it and reset m_bHasRect void CWebViewFolderIcon::_FlipFocusRect(BOOL RectState) { if (m_bHasRect != RectState) // needs flipping { m_bHasRect = RectState; ForceRedraw(); } return; } // Extract a ULONGLONG from two VARIANT's ULONGLONG CWebViewFolderIcon::GetUllMemFromVars(VARIANT *pvarHi, VARIANT *pvarLo) { ULARGE_INTEGER uli; uli.HighPart = pvarHi->ulVal; uli.LowPart = pvarLo->ulVal; return uli.QuadPart; } // Returns the integer percent from the string percent. Returns -1 if the string is invalid; int CWebViewFolderIcon::GetPercentFromStrW(LPCWSTR pwzPercent) { int percent = -1; int numchar = lstrlenW(pwzPercent); ASSERT(numchar>0); if (pwzPercent[numchar-1] == '%') { LPWSTR pwzTempPct = SysAllocString(pwzPercent); if (pwzTempPct) { pwzTempPct[numchar-1] = '\0'; for (int i=0 ; i < (numchar-2) ; i++) { if (!((pwzTempPct[i] >= '0') && (pwzTempPct[i] <= '9'))) { percent = 100; // 100% is the default to use in error conditions break; } } if ((-1 == percent) && !StrToIntExW(pwzTempPct, STIF_DEFAULT, &percent)) { percent = -1; } SysFreeString(pwzTempPct); } } return percent; } BOOL CWebViewFolderIcon::_WebViewOpen(void) { BOOL Processed = FALSE; if (IsSafeToDefaultVerb()) { Processed = TRUE; // // if the context menu option does not work, we try a shell execute on the pidl // if (FAILED(_DoContextMenuCmd(TRUE, 0, 0))) { if (m_pidl) { SHELLEXECUTEINFO sei = { 0 }; sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_INVOKEIDLIST; sei.nShow = SW_SHOWNORMAL; sei.lpIDList = m_pidl; if (!ShellExecuteEx(&sei)) { Processed = FALSE; } } } } return Processed; } void CWebViewFolderIcon::_ClearLabel(void) { if (m_pszDisplayName) { CoTaskMemFree(m_pszDisplayName); m_pszDisplayName = NULL; m_sizLabel.cx = m_sizLabel.cy = 0; } } void CWebViewFolderIcon::_GetLabel(IShellFolder *psf, LPCITEMIDLIST pidlItem) { if ((m_ViewUser & VIEW_WITHLABEL) && psf) { STRRET str; if (SUCCEEDED(psf->GetDisplayNameOf(pidlItem, SHGDN_INFOLDER, &str))) { AssertMsg(m_pszDisplayName == NULL, TEXT("CWebViewFolderIcon::_GetLabel - leaking m_pszDisplayName!")); StrRetToStr(&str, pidlItem, &m_pszDisplayName); } } } void CWebViewFolderIcon::_ClearAmbientFont(void) { if (m_pfont) // Font came from container { if (m_hfAmbient) m_pfont->ReleaseHfont(m_hfAmbient); m_pfont->Release(); m_pfont = NULL; } else // Font was created by us { if (m_hfAmbient) DeleteObject(m_hfAmbient); } m_hfAmbient = NULL; } void CWebViewFolderIcon::_GetAmbientFont(void) { if (!m_hfAmbient) { // Try to get the ambient font from our container if (SUCCEEDED(GetAmbientFont(&m_pfont))) { if (SUCCEEDED(m_pfont->get_hFont(&m_hfAmbient))) { // Yay, everybody is happy m_pfont->AddRefHfont(m_hfAmbient); } else { // Darn, couldn't get the font from container // Clean up and use the fallback _ClearAmbientFont(); goto fallback; } } else { fallback: // No ambient font -- use the icon title font LOGFONT lf; SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE); m_hfAmbient = CreateFontIndirect(&lf); } } } HRESULT CWebViewFolderIcon::InitImage(void) { HRESULT hr = E_FAIL; // Cancel pending bitmap request if you had a functioning IThumbnail // but didn't receive the bitmap if (m_pthumb && (m_hbm == NULL)) { m_pthumb->GetBitmap(NULL, 0, 0, 0); } m_dwThumbnailID++; // Initialize the image switch (_ViewType(m_ViewUser)) { case VIEW_THUMBVIEW: hr = InitThumbnail(); if (hr != S_OK) { // Default to icon view, but return the previous hr InitIcon(); } break; case VIEW_PIECHART: hr = InitPieGraph(); if (hr != S_OK) { // Default to icon view, but return the previous hr InitIcon(); } break; default: hr = InitIcon(); break; } if (SUCCEEDED(hr)) // Force a Redraw UpdateSize(); return hr; } HRESULT CWebViewFolderIcon::_GetPathW(LPWSTR psz) { *psz = 0; HRESULT hr = E_FAIL; LPITEMIDLIST pidl; if (S_OK == _GetFullPidl(&pidl)) { if (SHGetPathFromIDListW(pidl, psz)) hr = S_OK; ILFree(pidl); } return hr; } HRESULT CWebViewFolderIcon::InitPieGraph(void) { HRESULT hr = S_FALSE; WCHAR wzPath[MAX_PATH]; if (SUCCEEDED(_GetPathW(wzPath))) { // Check to see if it is a root if (PathIsRootW(wzPath)) { if (SUCCEEDED(ComputeFreeSpace(wzPath))) { m_ViewCurrent = VIEW_PIECHART; m_lImageHeight = PIEVIEW_DEFAULT; m_lImageWidth = PIEVIEW_DEFAULT; hr = S_OK; } } else // not the root, change view to large icon m_ViewCurrent = VIEW_LARGEICON; } return hr; } HRESULT CWebViewFolderIcon::InitThumbnail(void) { m_lImageHeight = THUMBVIEW_DEFAULT; m_lImageWidth = THUMBVIEW_DEFAULT; // Get thumbnail bitmap from the path HRESULT hr = S_FALSE; LPITEMIDLIST pidl; if (S_OK == _GetFullPidl(&pidl)) { hr = SetupIThumbnail(); if (SUCCEEDED(hr)) { LONG lWidth = _GetScaledImageWidth(); LONG lHeight = _GetScaledImageHeight(); // Sends the WM_HTML_BITMAP message hr = m_pthumb->GetBitmapFromIDList(pidl, m_dwThumbnailID, lWidth, lHeight); if (SUCCEEDED(hr)) m_ViewCurrent = VIEW_THUMBVIEW; else hr = S_FALSE; } ILFree(pidl); } return hr; } HRESULT CWebViewFolderIcon::_MakeRoomForLabel() { /* * If we got a label, then make room for it. */ if (m_pszDisplayName) { GETDCSTATE dcs; HDC hdc = IUnknown_GetDC(m_spClientSite, &m_rcPos, &dcs); _GetAmbientFont(); HFONT hfPrev = SelectFont(hdc, m_hfAmbient); m_sizLabel.cx = m_sizLabel.cy = 0; GetTextExtentPoint(hdc, m_pszDisplayName, lstrlen(m_pszDisplayName), &m_sizLabel); SelectFont(hdc, hfPrev); IUnknown_ReleaseDC(hdc, &dcs); } return S_OK; } HRESULT CWebViewFolderIcon::InitIcon(void) { LPITEMIDLIST pidlLast; CComPtr spsfParent; INT iIconIndex = II_DESKTOP; _ClearLabel(); // Get icon index HRESULT hr = _GetPidlAndShellFolder(&pidlLast, &spsfParent); if (SUCCEEDED(hr)) { if (m_ViewUser & VIEW_WITHLABEL) { _GetLabel(spsfParent, pidlLast); } // _GetPidlAndShellFolder() may succeed and spsfParent and pidlLast can be NULL. // In this case the icon will default to II_FOLDER // Is it the default folder case? if (hr == S_FALSE) { // Yes, so just use the default folder icon. iIconIndex = II_FOLDER; } else if (spsfParent && pidlLast) { iIconIndex = SHMapPIDLToSystemImageListIndex(spsfParent, pidlLast, NULL); if (iIconIndex <= 0) { iIconIndex = II_FOLDER; } } // else it defaults to the desktop // Extract icon hr = E_FAIL; // We haven't gotten it yet if (m_hIcon) { // If the indexes match, we can use the previous value as a cache, otherwise, // we need to free it. We also need to free the bitmap in this case. if (iIconIndex != m_iIconIndex) { DestroyIcon(m_hIcon); m_hIcon = 0; } else { hr = S_OK; // Use the one we have already } } // We also need to check and free the bitmap if (m_hbm) { DeleteObject(m_hbm); m_hbm = 0; } if (FAILED(hr)) // Different icon { HIMAGELIST himlSysLarge; HIMAGELIST himlSysSmall; if ((iIconIndex > 0) && Shell_GetImageLists(&himlSysLarge, &himlSysSmall)) { switch (_ViewType(m_ViewUser)) { case VIEW_SMALLICON: m_hIcon = ImageList_GetIcon(himlSysSmall, iIconIndex, 0); m_ViewCurrent = m_ViewUser; break; case VIEW_LARGEICON: m_hIcon = ImageList_GetIcon(himlSysLarge, iIconIndex, 0); m_ViewCurrent = m_ViewUser; break; default: // Falls here for large icon and default m_hIcon = ImageList_GetIcon(himlSysLarge, iIconIndex, 0); m_ViewCurrent = VIEW_LARGEICON; break; } // switch if (m_hIcon) { ICONINFO iconinfo; // Get icon size if (GetIconInfo(m_hIcon, &iconinfo)) { BITMAP bm; if (GetObject(iconinfo.hbmColor, sizeof(bm), &bm)) { m_lImageWidth = bm.bmWidth; m_lImageHeight = bm.bmHeight; // Hold on to the color hbm for use as a drag image. m_hbm = iconinfo.hbmColor; hr = S_OK; } else { DeleteObject(iconinfo.hbmColor); } DeleteObject(iconinfo.hbmMask); } } } } ILFree(pidlLast); _MakeRoomForLabel(); } if (FAILED(hr)) { // Couldn't get the icon so set the size to something resonable so that the rest // of the page looks normal m_lImageWidth = LARGE_ICON_DEFAULT; m_lImageHeight = LARGE_ICON_DEFAULT; UpdateSize(); // Force an update } return hr; } HRESULT CWebViewFolderIcon::UpdateSize(void) { HRESULT hr = E_FAIL; // Get the IHtmlStyle if (m_spClientSite) { CComPtr spControlSite; hr = m_spClientSite->QueryInterface(IID_PPV_ARG(IOleControlSite, &spControlSite)); if (EVAL(SUCCEEDED(hr))) { CComPtr spdisp; hr = spControlSite->GetExtendedControl(&spdisp); if (EVAL(SUCCEEDED(hr))) { CComPtr spElement; hr = spdisp->QueryInterface(IID_PPV_ARG(IHTMLElement, &spElement)); if (EVAL(SUCCEEDED(hr))) { CComPtr spStyle; hr = spElement->get_style(&spStyle); if (EVAL(SUCCEEDED(hr))) { CComVariant vWidth(_GetControlWidth(), VT_I4); CComVariant vHeight(_GetControlHeight(), VT_I4); // Set the height and width spStyle->put_width(vWidth); spStyle->put_height(vHeight); } } } } } return hr; } HRESULT CWebViewFolderIcon::ForceRedraw(void) { IOleInPlaceSiteEx *pins; // Get the IHtmlStyle if (m_spClientSite) { if (SUCCEEDED(m_spClientSite->QueryInterface(IID_PPV_ARG(IOleInPlaceSiteEx, &pins)))) { HWND hwnd; if (SUCCEEDED(pins->GetWindow(&hwnd))) { ::InvalidateRgn(hwnd, NULL, TRUE); } pins->Release(); } } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IOleInPlaceObject STDMETHODIMP CWebViewFolderIcon::UIDeactivate(void) { if (m_bAdvPropsOn) _FlipFocusRect(FALSE); return IOleInPlaceObject_UIDeactivate(); } // *** IOleInPlaceActiveObject *** HRESULT CWebViewFolderIcon::TranslateAccelerator(LPMSG pMsg) { HRESULT hr = S_OK; if (!m_fTabRecieved) { hr = IOleInPlaceActiveObjectImpl::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 (hr != S_OK && pMsg && (pMsg->wParam == VK_TAB || pMsg->wParam == VK_F6) && m_spClientSite) { HWND hwnd; if (SUCCEEDED(_GetHwnd(&hwnd)) && (GetFocus() != hwnd)) { ::SetFocus(hwnd); hr = S_OK; } else { IOleControlSite* pocs = NULL; if (SUCCEEDED(m_spClientSite->QueryInterface(IID_PPV_ARG(IOleControlSite, &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; hr = pocs->TranslateAccelerator(pMsg, grfModifiers); m_fTabRecieved = FALSE; } } } } return hr; } ///////////////////////////////////////////////////////////////////////////// // ATL HRESULT CWebViewFolderIcon::DoVerbUIActivate(LPCRECT prcPosRect, HWND hwndParent) { if (m_bAdvPropsOn) _FlipFocusRect(TRUE); return IOleObjectImpl::DoVerbUIActivate(prcPosRect, hwndParent); } ///////////////////////////////////////////////////////////////////////////// // IDispatch STDMETHODIMP CWebViewFolderIcon::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { HRESULT hr; // // We are overloading this dispatch implementation to be an html window event // sink and implement the scale property. This is safe since the dispid ranges // don't overlap. // Likewise we overload now for notifications that come from the browser object... // if (dispidMember == DISPID_HTMLWINDOWEVENTS_ONLOAD) { hr = OnWindowLoad(); } else if (dispidMember == DISPID_HTMLWINDOWEVENTS_ONUNLOAD) { hr = OnWindowUnLoad(); } else { hr = IDispatchImpl::Invoke( dispidMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); } return hr; } ///////////////////////////////////////////////////////////////////////////// // IViewObjectEx STDMETHODIMP CWebViewFolderIcon::GetViewStatus(DWORD* pdwStatus) { *pdwStatus = VIEWSTATUS_DVASPECTTRANSPARENT; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IPointerInactive STDMETHODIMP CWebViewFolderIcon::GetActivationPolicy(DWORD* pdwPolicy) { if (!m_bAdvPropsOn) return S_OK; *pdwPolicy = POINTERINACTIVE_ACTIVATEONDRAG; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IOleInPlaceObjectWindowless // To implement Windowless DropTarget STDMETHODIMP CWebViewFolderIcon::GetDropTarget(IDropTarget **ppDropTarget) { HRESULT hr = S_OK; if (ppDropTarget) *ppDropTarget = NULL; if (m_bAdvPropsOn) { // Do we need to populate m_pDropTargetCache? if (!m_pDropTargetCache) { // Yes, so try to get it now. hr = _GetChildUIObjectOf(IID_PPV_ARG(IDropTarget, &m_pDropTargetCache)); } if (m_pDropTargetCache) hr = m_pDropTargetCache->QueryInterface(IID_PPV_ARG(IDropTarget, ppDropTarget)); else hr = E_FAIL; } return hr; } ///////////////////////////////////////////////////////////////////////////// // IOleObject STDMETHODIMP CWebViewFolderIcon::SetClientSite(IOleClientSite *pClientSite) { HRESULT hr; // Deal with the old client site if (pClientSite == NULL && m_spClientSite) { // We need to unadvise from the defview object now... if (m_pccpDV) { m_pccpDV->Unadvise(m_dwCookieDV); m_pccpDV->Release(); m_pccpDV = NULL; } DisconnectHtmlEvents(m_pdispWindow, m_dwHtmlWindowAdviseCookie); m_dwHtmlWindowAdviseCookie = 0; } hr = IOleObjectImpl::SetClientSite(pClientSite); if ((pClientSite != NULL) && SUCCEEDED(hr)) { ConnectHtmlEvents(this, m_spClientSite, &m_pdispWindow, &m_dwHtmlWindowAdviseCookie); // OK now lets register ourself with the Defview to get any events that they may generate... IServiceProvider *pspTLB; hr = IUnknown_QueryService(m_spClientSite, SID_STopLevelBrowser, IID_PPV_ARG(IServiceProvider, &pspTLB)); if (SUCCEEDED(hr)) { IExpDispSupport *peds; hr = pspTLB->QueryService(IID_IExpDispSupport, IID_PPV_ARG(IExpDispSupport, &peds)); if (SUCCEEDED(hr)) { hr = peds->FindCIE4ConnectionPoint(DIID_DWebBrowserEvents2, &m_pccpDV); if (SUCCEEDED(hr)) { hr = m_pccpDV->Advise(SAFECAST(this, IDispatch*), &m_dwCookieDV); } peds->Release(); } pspTLB->Release(); } } return hr; } UINT g_cfPreferedEffect = 0; HRESULT _SetPreferedDropEffect(IDataObject *pdtobj, DWORD dwEffect) { if (g_cfPreferedEffect == 0) g_cfPreferedEffect = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT); HRESULT hr = E_OUTOFMEMORY; DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD)); if (pdw) { STGMEDIUM medium; FORMATETC fmte = {(CLIPFORMAT)g_cfPreferedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; *pdw = dwEffect; medium.tymed = TYMED_HGLOBAL; medium.hGlobal = pdw; medium.pUnkForRelease = NULL; hr = pdtobj->SetData(&fmte, &medium, TRUE); if (FAILED(hr)) GlobalFree((HGLOBAL)pdw); } return hr; } ///////////////////////////////////////////////////////////////////////////// // Event Handlers HRESULT CWebViewFolderIcon::DragDrop(int iClickXPos, int iClickYPos) { if (!m_bAdvPropsOn) return S_OK; LPITEMIDLIST pidlLast; IShellFolder *psfParent; HRESULT hr = _GetPidlAndShellFolder(&pidlLast, &psfParent); if (hr == S_OK) { IDataObject *pdtobj; hr = psfParent->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*) &pidlLast, IID_PPV_ARG_NULL(IDataObject, &pdtobj)); if (SUCCEEDED(hr)) { DWORD dwEffect = DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK; psfParent->GetAttributesOf(1, (LPCITEMIDLIST*) &pidlLast, &dwEffect); dwEffect &= DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK; if (dwEffect) { HRESULT hrOleInit = SHCoInitialize(); HWND hwnd; hr = _GetHwnd(&hwnd); if (SUCCEEDED(hr)) { DWORD dwEffectOut; _SetPreferedDropEffect(pdtobj, DROPEFFECT_LINK); // Set the drag image and effect; we don't care if // it fails, we'll just use the default. _SetDragImage(iClickXPos, iClickYPos, pdtobj); hr = SHDoDragDrop(hwnd, pdtobj, NULL, dwEffect, &dwEffectOut); } SHCoUninitialize(hrOleInit); } pdtobj->Release(); } psfParent->Release(); ILFree(pidlLast); } return hr; } // SetDragImage // // Sets the drag image to be identical to the icon HRESULT CWebViewFolderIcon::_SetDragImage(int iClickXPos, int iClickYPos, IDataObject *pdtobj) { // Check things that need to be valid for us to work AssertMsg(m_hdc != NULL , TEXT("CWebViewFolderIcon:_SetDragImage() m_hdc is null")); AssertMsg(m_hbmDrag != NULL, TEXT("CWebViewFolderIcon:_SetDragImage m_hbmDrag is null")); // If the image is a pie chart, it isn't loaded into m_hbm, so we need // to do that first if (m_ViewCurrent == VIEW_PIECHART) { _GetPieChartIntoBitmap(); } // Get a dragdrop helper to set our image IDragSourceHelper *pdsh; HRESULT hr = CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IDragSourceHelper, &pdsh)); if (SUCCEEDED(hr)) { BITMAPINFOHEADER bmi = {0}; BITMAP bm = {0}; UINT uBufferOffset = 0; // This is a screwy procedure to use GetDIBits. // See knowledge base Q80080 GetObject(m_hbm, sizeof(BITMAP), &bm); bmi.biSize = sizeof(BITMAPINFOHEADER); bmi.biWidth = bm.bmWidth; bmi.biHeight = bm.bmHeight; bmi.biPlanes = 1; bmi.biBitCount = bm.bmPlanes * bm.bmBitsPixel; // This needs to be one of these 4 values if (bmi.biBitCount <= 1) bmi.biBitCount = 1; else if (bmi.biBitCount <= 4) bmi.biBitCount = 4; else if (bmi.biBitCount <= 8) bmi.biBitCount = 8; else bmi.biBitCount = 24; bmi.biCompression = BI_RGB; // Total size of buffer for info struct and color table uBufferOffset = sizeof(BITMAPINFOHEADER) + ((bmi.biBitCount == 24) ? 0 : ((1 << bmi.biBitCount) * sizeof(RGBQUAD))); // Buffer for bitmap bits, so we can copy them. BYTE * psBits = (BYTE *) SHAlloc(uBufferOffset); if (psBits) { // Put bmi into the memory block CopyMemory(psBits, &bmi, sizeof(BITMAPINFOHEADER)); // Get the size of the buffer needed for bitmap bits if (GetDIBits(m_hdc, m_hbm, 0, 0, NULL, (BITMAPINFO *) psBits, DIB_RGB_COLORS)) { // Realloc our buffer to be big enough psBits = (BYTE *) SHRealloc(psBits, uBufferOffset + ((BITMAPINFOHEADER *) psBits)->biSizeImage); if (psBits) { // Fill the buffer if (GetDIBits(m_hdc, m_hbm, 0, bmi.biHeight, (void *)(psBits + uBufferOffset), (BITMAPINFO *)psBits, DIB_RGB_COLORS)) { SHDRAGIMAGE shdi; // Drag images struct shdi.hbmpDragImage = CreateBitmapIndirect(&bm); if (shdi.hbmpDragImage) { // Set the drag image bitmap if (SetDIBits(m_hdc, shdi.hbmpDragImage, 0, m_lImageHeight, (void *)(psBits + uBufferOffset), (BITMAPINFO *)psBits, DIB_RGB_COLORS)) { // Populate the drag image structure shdi.sizeDragImage.cx = m_lImageWidth; shdi.sizeDragImage.cy = m_lImageHeight; shdi.ptOffset.x = iClickXPos - m_rcPos.left; shdi.ptOffset.y = iClickYPos - m_rcPos.top; shdi.crColorKey = 0; // Set the drag image hr = pdsh->InitializeFromBitmap(&shdi, pdtobj); } else { hr = E_FAIL; // Can't SetDIBits } } else { hr = E_OUTOFMEMORY; // Can't alloc hbmpDragImage } } else { hr = E_FAIL; // Can't fill psBits } // Free psBits below... } else { hr = E_OUTOFMEMORY; // Can't realloc psBits // Free psbits here; it still has the old contents SHFree(psBits); psBits = NULL; } } else { hr = E_FAIL; // Can't get image size } if (psBits) SHFree(psBits); } else { hr = E_OUTOFMEMORY; // Can't alloc psBits } pdsh->Release(); } return hr; } HRESULT CWebViewFolderIcon::_GetPieChartIntoBitmap() { BITMAP bm; // It is possible for m_hbm to be alloced, so check for it. if (m_hbm) { DeleteObject(m_hbm); } // Notice that because we want to draw into a new DC starting // from the origin, but our rect contains the coords for the // original DC, it is neccessary to adjust the coords so that // the rect starts at 0, 0 but still has the same proportions. // Since OnDraw() resets the rect each time, we don't have to // preserve it and do have to do this each time. Finally, since // Draw3dPie adjusts the rect dimensions for itself, we only want // to fix this once. if (!m_fRectAdjusted) { m_rect.right -= m_rect.left; m_rect.left = 0; m_rect.bottom -= m_rect.top; m_rect.top = 0; m_fRectAdjusted = 1; } // Get the bitmap GetObject(m_hbmDrag, sizeof(BITMAP), &bm); m_hbm = CreateBitmapIndirect(&bm); if (m_hbm) { // Select into the new DC, and draw our pie HBITMAP hbmOld = (HBITMAP) SelectObject(m_hdc, m_hbm); DWORD dwPercent1000 = 0; if (EVAL((m_ullTotalSpace > 0) && (m_ullFreeSpace <= m_ullTotalSpace))) { ComputeSlicePct(m_ullUsedSpace, &dwPercent1000); } Draw3dPie(m_hdc, &m_rect, dwPercent1000, m_ChartColors); SelectObject(m_hdc, hbmOld); } return S_OK; } LRESULT CWebViewFolderIcon::OnInitPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { if (m_pcm3) m_pcm3->HandleMenuMsg(uMsg, wParam, lParam); return 0; } LRESULT CWebViewFolderIcon::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { if (!m_bAdvPropsOn) return TRUE; if ((int)wParam != VK_RETURN && (int) wParam != VK_SPACE) { return FALSE; } else return _WebViewOpen(); } LRESULT CWebViewFolderIcon::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { if (m_bAdvPropsOn) { _DisplayContextMenu(-1, -1); } return TRUE; } // NOTE: our drag drop code captures the mouse and has to do funky stuff to // make sure we get this button up message. if you have problems with this check // the code in CheckForDragBegin() LRESULT CWebViewFolderIcon::OnButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { BOOL Processed = FALSE; if (!m_bAdvPropsOn) return TRUE; HWND hwnd; if (EVAL(SUCCEEDED(_GetHwnd(&hwnd)))) { if (CheckForDragBegin(hwnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) { IUnknown *punk; if (EVAL(SUCCEEDED(IUnknown_QueryService(m_spClientSite, SID_STopLevelBrowser, IID_PPV_ARG(IUnknown, &punk))))) { if (SUCCEEDED(DragDrop(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))) { Processed = TRUE; } } } } /* * In single-click mode, open on single left click. */ if (!Processed && uMsg == WM_LBUTTONDOWN && m_clickStyle == 1) return _WebViewOpen(); return Processed; } // Only valid for the HTML window case LRESULT CWebViewFolderIcon::OnLButtonDoubleClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { if (!m_bAdvPropsOn || m_clickStyle != 2) return TRUE; return _WebViewOpen(); } LRESULT CWebViewFolderIcon::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { if (!m_bAdvPropsOn) return TRUE; // // the first time we get a WM_MOUSEMOVE event, we set m_bHilite to be TRUE and ignore // subsequent WM_MOUSEMOVEs. OnMouseLeave() sets m_bHilite to FALSE in response to // a WM_MOUSELEAVE msg. // if (!m_bHilite) { m_bHilite = TRUE; return SUCCEEDED(ForceRedraw()); } else { return TRUE; } } LRESULT CWebViewFolderIcon::OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { if (!m_bAdvPropsOn) return TRUE; m_bHilite = FALSE; return SUCCEEDED(ForceRedraw()); } // The Right Mouse button came up so we want to LRESULT CWebViewFolderIcon::OnRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { LRESULT lResult = FALSE; if (!m_bAdvPropsOn) return TRUE; HRESULT hr = _IsSafe(); if (S_OK == hr) { hr = _DisplayContextMenu(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); if (SUCCEEDED(hr)) { lResult = TRUE; } } return lResult; } BOOL CWebViewFolderIcon::_IsHostWebView(void) { if (UNINITIALIZE_BOOL == m_fIsHostWebView) { CComPtr spDefView; m_fIsHostWebView = FALSE; // This will fail if we are hosted in a web page instead of the HTML WebView frame in DefView. if (SUCCEEDED(IUnknown_QueryService(m_spClientSite, SID_SFolderView, IID_PPV_ARG(IDefViewID, &spDefView)))) { m_fIsHostWebView = TRUE; } } return m_fIsHostWebView; } BOOL CWebViewFolderIcon::_IsPubWizHosted(void) { IPropertyBag *ppb; HRESULT hr = IUnknown_QueryService(m_spClientSite, SID_WebWizardHost, IID_PPV_ARG(IPropertyBag, &ppb)); if (SUCCEEDED(hr)) { ppb->Release(); } return SUCCEEDED(hr); } /****************************************************\ DESCRIPTION: We need a little special work on the Context Menu since it points to the same folder we are in. So the "Send To" menu needs massaging and the "Open" verb needs to be removed. TODO: I think we should also do this: case WM_MENUCHAR: _pcm->HandleMenuMsg2(uMsg, wParam, lParam, &lres); break; case WM_DRAWITEM: case WM_MEASUREITEM: _pcm->HandleMenuMsg(uMsg, wParam, lParam); break; case WM_INITMENUPOPUP: _pcm->HandleMenuMsg(WM_INITMENUPOPUP, (WPARAM)hmenuPopup, (LPARAM)MAKELONG(nIndex, fSystemMenu) break; \****************************************************/ HRESULT CWebViewFolderIcon::_DisplayContextMenu(long nXCord, long nYCord) { if (!m_bAdvPropsOn) { return S_OK; } // respect system policies if (SHRestricted(REST_NOVIEWCONTEXTMENU)) { return E_FAIL; } return _DoContextMenuCmd(FALSE, nXCord, nYCord); } // // bDefault == TRUE > Function executes the default context menu verb, ignores the coords // bDefault == FALSE > Function pops up a menu at the given coords and executes the desired verb // HRESULT CWebViewFolderIcon::_DoContextMenuCmd(BOOL bDefault, long nXCord, long nYCord) { IContextMenu *pcm; HRESULT hr = _GetChildUIObjectOf(IID_PPV_ARG(IContextMenu, &pcm)); if (SUCCEEDED(hr)) { HMENU hpopup = CreatePopupMenu(); if (hpopup) { // SetSite required if you want in place navigation IUnknown_SetSite(pcm, m_spClientSite); hr = pcm->QueryContextMenu(hpopup, 0, ID_FIRST, ID_LAST, CMF_NORMAL); if (SUCCEEDED(hr)) { HWND hwnd; hr = _GetHwnd(&hwnd); if (SUCCEEDED(hr)) { UINT idCmd = -1; if (bDefault) // invoke the default verb { idCmd = GetMenuDefaultItem(hpopup, FALSE, GMDI_GOINTOPOPUPS); } else { // // popup the menu and get the command to be executed // POINT point = {nXCord, nYCord}; // NTRAID#106655 05-02-2000 arisha // We need to add support to be able to modify the context menu from script. // Below, we make sure we do not remove the "open" verb from the context // menu if we are displaying it in the VIEW_LARGEICONLABEL mode. if (_IsHostWebView() && (m_ViewCurrent != VIEW_LARGEICONLABEL)) { hr = ContextMenu_DeleteCommandByName(pcm, hpopup, ID_FIRST, TEXT("open")); } if ((point.x == -1) && (point.y == -1)) { _GetCenterPoint(&point); } ::ClientToScreen(hwnd, &point); pcm->QueryInterface(IID_PPV_ARG(IContextMenu3, &m_pcm3)); if (SUCCEEDED(_SetupWindow())) { idCmd = TrackPopupMenu(hpopup, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN, (int)point.x, (int)point.y, 0, m_msgHwnd, NULL); } if (!IsSafeToDefaultVerb() || 0 == idCmd) // 0 implies user cancelled selection { idCmd = -1; } ATOMICRELEASE(m_pcm3); } if (idCmd != -1) { CMINVOKECOMMANDINFO cmdInfo = { sizeof(cmdInfo), 0, hwnd, (LPSTR)MAKEINTRESOURCE(idCmd), NULL, NULL, SW_NORMAL }; hr = pcm->InvokeCommand(&cmdInfo); } } } IUnknown_SetSite(pcm, NULL); DestroyMenu(hpopup); } pcm->Release(); } return hr; } HRESULT CWebViewFolderIcon::OnAmbientPropertyChange(DISPID dispid) { switch (dispid) { case DISPID_UNKNOWN: case DISPID_AMBIENT_FONT: // changing the font means we need to recompute our label if (m_pszDisplayName) { CComPtr spFont; if (SUCCEEDED(GetAmbientFont(&spFont))) { if (spFont->IsEqual(m_pfont) != S_OK) { _ClearAmbientFont(); _MakeRoomForLabel(); } } } // FALL THROUGH case DISPID_AMBIENT_BACKCOLOR: case DISPID_AMBIENT_FORECOLOR: ForceRedraw(); break; } return S_OK; } COLORREF _TranslateColor(OLE_COLOR oclr) { COLORREF clr; if (FAILED(OleTranslateColor(oclr, NULL, &clr))) clr = oclr; return clr; } HRESULT CWebViewFolderIcon::OnDraw(ATL_DRAWINFO& di) { RECT& rc = *(RECT*)di.prcBounds; LONG lImageWidth = _GetScaledImageWidth(); LONG lImageHeight = _GetScaledImageHeight(); // Grab our hdc and rect to be used in _SetDragImage if (m_hdc) { DeleteDC(m_hdc); } m_hdc = CreateCompatibleDC(di.hdcDraw); if (m_hbmDrag) { DeleteObject(m_hbmDrag); } m_hbmDrag = CreateCompatibleBitmap(di.hdcDraw, m_lImageWidth, m_lImageHeight); m_rect = rc; m_fRectAdjusted = 0; // // Draw the folder icon // if ((m_ViewCurrent == VIEW_THUMBVIEW) || (m_ViewCurrent == VIEW_PIECHART)) { HDC hdc = di.hdcDraw; HDC hdcBitmap; BITMAP bm; HPALETTE hpal = NULL; ASSERT(hdc); // 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); } hdcBitmap = CreateCompatibleDC(hdc); if (hdcBitmap) { // Draw pie chart if (m_ViewCurrent == VIEW_PIECHART) { DWORD dwPercent1000 = 0; if (1) // m_fUseSystemColors. When do we want this off? { // system colors can change! m_ChartColors[PIE_USEDCOLOR] = GetSysColor(COLOR_3DFACE); m_ChartColors[PIE_FREECOLOR] = GetSysColor(COLOR_3DHILIGHT); m_ChartColors[PIE_USEDSHADOW] = GetSysColor(COLOR_3DSHADOW); m_ChartColors[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_ChartColors[dw] = GetNearestColor(hdc, m_ChartColors[dw]); } } if (EVAL((m_ullTotalSpace > 0) && (m_ullFreeSpace <= m_ullTotalSpace))) { ComputeSlicePct(m_ullUsedSpace, &dwPercent1000); } Draw3dPie(hdc, &rc, dwPercent1000, m_ChartColors); } else // Draw the Bitmap { SelectObject(hdcBitmap, m_hbm); GetObject(m_hbm, sizeof(bm), &bm); // Bitmap exactly fits the rectangle 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); } // Stretch Bitmap to fit the rectangle else { SetStretchBltMode(hdc, COLORONCOLOR); StretchBlt(hdc, rc.left, rc.top, lImageWidth, lImageHeight, hdcBitmap, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); } } DeleteDC(hdcBitmap); } } else if (m_hIcon) { DrawIconEx(di.hdcDraw, rc.left, rc.top, m_hIcon, lImageWidth, lImageHeight, 0, 0, DI_NORMAL); } // Draw the label (if any) if (m_pszDisplayName) { TEXTMETRIC tm; TCHAR szFace[32]; HFONT hFontHilite = NULL; // // first get the current font properties, there seems to be no straightforward way // to just obtain the LOGFONT structure from an HFONT object, so we have to select it // to a DC, then obtain the text metrics and use them to create a new font with or // without the underline based on m_bHilite value. // HFONT hfPrev = SelectFont(di.hdcDraw, m_hfAmbient); GetTextFace(di.hdcDraw,ARRAYSIZE(szFace), szFace); if (szFace[0] && GetTextMetrics(di.hdcDraw,&tm)) { hFontHilite = CreateFont(tm.tmHeight, tm.tmAveCharWidth, 0, //Escapement, 0, //Orientation, tm.tmWeight, (DWORD) tm.tmItalic, (DWORD) m_bHilite, // Hilite is by underlining tm.tmStruckOut, tm.tmCharSet, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, tm.tmPitchAndFamily, szFace); if (hFontHilite) { SelectFont(di.hdcDraw, hFontHilite); } } OLE_COLOR oclrTxt, oclrBk; COLORREF clrTxtPrev, clrBkPrev; HRESULT hrTxt, hrBk; hrTxt = GetAmbientForeColor(oclrTxt); if (SUCCEEDED(hrTxt)) clrTxtPrev = SetTextColor(di.hdcDraw, _TranslateColor(oclrTxt)); hrBk = GetAmbientBackColor(oclrBk); if (SUCCEEDED(hrBk)) clrBkPrev = SetBkColor(di.hdcDraw, _TranslateColor(oclrBk)); TextOut(di.hdcDraw, rc.left + lImageWidth + m_cxLabelGap, rc.top + lImageHeight/2 - m_sizLabel.cy/2, m_pszDisplayName, lstrlen(m_pszDisplayName)); if (m_bHasRect) { RECT rcFocus; rcFocus.top = rc.top + lImageHeight/2 - m_sizLabel.cy/2; rcFocus.bottom = rcFocus.top + m_sizLabel.cy; rcFocus.left = rc.left + lImageWidth + m_cxLabelGap - 1; rcFocus.right = rcFocus.left + m_sizLabel.cx + 1; DrawFocusRect(di.hdcDraw, &rcFocus); } if (SUCCEEDED(hrTxt)) SetTextColor(di.hdcDraw, clrTxtPrev); if (SUCCEEDED(hrBk)) SetBkColor(di.hdcDraw, clrBkPrev); SelectFont(di.hdcDraw, hfPrev); if (hFontHilite) { DeleteObject(hFontHilite); hFontHilite = NULL; } } return S_OK; } HRESULT CWebViewFolderIcon::OnWindowLoad() { return InitImage(); } HRESULT CWebViewFolderIcon::OnImageChanged() { HRESULT hr = InitImage(); if (SUCCEEDED(hr)) ForceRedraw(); return hr; } HRESULT CWebViewFolderIcon::OnWindowUnLoad() { // nothing here now... return S_OK; } STDMETHODIMP CWebViewFolderIcon::get_scale(BSTR *pbstrScale) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { WCHAR wzScale[MAX_SCALE_STR]; wnsprintfW(wzScale, ARRAYSIZE(wzScale), L"%d", m_percentScale); *pbstrScale = SysAllocString(wzScale); return S_OK; } } STDMETHODIMP CWebViewFolderIcon::put_scale(BSTR bstrScale) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { int numchar = lstrlenW(bstrScale); int tempScale = 0; if (numchar && bstrScale[numchar-1] == '%') { tempScale = GetPercentFromStrW(bstrScale); } else { // valid number for (int i=0 ; i < (numchar-2) ; i++) { if (!((bstrScale[i] >= '0') && (bstrScale[i] <= '9'))) { tempScale = -1; break; } } if ((tempScale != -1) && !StrToIntExW(bstrScale, STIF_DEFAULT, &tempScale)) { tempScale = -1; } } if (tempScale > 0) { if (m_percentScale != tempScale) { m_percentScale = tempScale; return UpdateSize(); } else return S_OK; } return S_FALSE; } } STDMETHODIMP CWebViewFolderIcon::get_advproperty(VARIANT_BOOL *pvarbAdvProp) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { *pvarbAdvProp = (VARIANT_BOOL)m_bAdvPropsOn; return S_OK; } } STDMETHODIMP CWebViewFolderIcon::put_advproperty(VARIANT_BOOL varbAdvProp) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { if (varbAdvProp != m_bAdvPropsOn) { m_bAdvPropsOn = varbAdvProp; return OnImageChanged(); } return S_OK; } } STDMETHODIMP CWebViewFolderIcon::get_view(BSTR *pbstrView) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { HRESULT hr = S_FALSE; LPCWSTR pwzTempView; switch (m_ViewCurrent) { case VIEW_THUMBVIEW: { pwzTempView = SZ_THUMB_VIEW; break; } case VIEW_PIECHART: { pwzTempView = SZ_PIE_VIEW; break; } case VIEW_SMALLICON: { pwzTempView = SZ_SMALL_ICON; break; } case VIEW_SMALLICONLABEL: { pwzTempView = SZ_SMALL_ICON_LABEL; break; } case VIEW_LARGEICONLABEL: { pwzTempView = SZ_LARGE_ICON_LABEL; break; } default: // default and large icon { pwzTempView = SZ_LARGE_ICON; break; } } *pbstrView = SysAllocString(pwzTempView); if (*pbstrView) hr = S_OK; return hr; } } STDMETHODIMP CWebViewFolderIcon::put_view(BSTR bstrView) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { HRESULT hr = S_OK; VIEWS View = VIEW_LARGEICON; if (StrCmpIW(bstrView, SZ_LARGE_ICON) == 0) { View = VIEW_LARGEICON; } else if (StrCmpIW(bstrView, SZ_SMALL_ICON) == 0) { View = VIEW_SMALLICON; } else if (StrCmpIW(bstrView, SZ_SMALL_ICON_LABEL) == 0) { View = VIEW_SMALLICONLABEL; } else if (StrCmpIW(bstrView, SZ_LARGE_ICON_LABEL) == 0) { View = VIEW_LARGEICONLABEL; } else if (StrCmpIW(bstrView, SZ_THUMB_VIEW) == 0) { View = VIEW_THUMBVIEW; } else if (StrCmpIW(bstrView, SZ_PIE_VIEW) == 0) { View = VIEW_PIECHART; } else hr = S_FALSE; if ((S_OK == hr) && (m_ViewUser != View)) { m_ViewUser = View; hr = OnImageChanged(); } return hr; } } /**************************************************************\ DESCRIPTION: The caller is getting the path of our control. SECURITY: We only trust callers from safe pages. This method secifically worries about untrusted callers using us to find out what paths on the file system exists or don't exist. \**************************************************************/ STDMETHODIMP CWebViewFolderIcon::get_path(BSTR *pbstrPath) { AssertMsg((NULL != m_spClientSite.p), TEXT("CWebViewFolderIcon::get_path() We need m_spClientSite for our security test and it's NULL. BAD, BAD, BAD!")); HRESULT hr; if (S_OK != _IsSafe()) { // 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. hr = E_ACCESSDENIED; } else { LPITEMIDLIST pidlFull; hr = S_FALSE; *pbstrPath = NULL; if (S_OK == _GetFullPidl(&pidlFull)) { WCHAR wzPath[INTERNET_MAX_URL_LENGTH]; if (S_OK == SHGetNameAndFlagsW(pidlFull, SHGDN_FORPARSING, wzPath, ARRAYSIZE(wzPath), NULL)) { *pbstrPath = SysAllocString(wzPath); if (*pbstrPath) hr = S_OK; } ILFree(pidlFull); } } return hr; } /**************************************************************\ DESCRIPTION: The caller is setting the path of our control. Our control will render a view of this item, which is often and icon. SECURITY: We only trust callers from safe pages. This method secifically worries about untrusted callers using us to find out what paths on the file system exists or don't exist. \**************************************************************/ STDMETHODIMP CWebViewFolderIcon::put_path(BSTR bstrPath) { AssertMsg((NULL != m_spClientSite.p), TEXT("CWebViewFolderIcon::put_path() We need m_spClientSite for our security test and it's NULL. BAD, BAD, BAD!")); HRESULT hr; if (S_OK != _IsSafe()) { // 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. hr = E_ACCESSDENIED; } else { hr = S_FALSE; LPITEMIDLIST pidlNew; hr = IEParseDisplayNameW(CP_ACP, bstrPath, &pidlNew); if (SUCCEEDED(hr)) { ATOMICRELEASE(m_pDropTargetCache); // We will want another IDropTarget for this new pidl. ILFree(m_pidl); m_pidl = pidlNew; hr = OnImageChanged(); AssertMsg(SUCCEEDED(hr), TEXT("CWebViewFolderIcon::put_path() failed to create the image so the image will be incorrect. Please find out why.")); hr = S_OK; } } return hr; } // Automation methods to get/put FolderItem objects from FolderIcon STDMETHODIMP CWebViewFolderIcon::get_item(FolderItem ** ppFolderItem) { HRESULT hr; if (S_OK != _IsSafe()) { // 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. hr = E_ACCESSDENIED; } else { LPITEMIDLIST pidlFull; *ppFolderItem = NULL; hr = _GetFullPidl(&pidlFull); if ((hr == S_OK) && pidlFull) { IShellDispatch * psd; hr = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellDispatch, &psd)); if (SUCCEEDED(hr)) { IObjectSafety * pos; hr = psd->QueryInterface(IID_PPV_ARG(IObjectSafety, &pos)); if (SUCCEEDED(hr)) { // Simulate what trident does. hr = pos->SetInterfaceSafetyOptions(IID_IDispatch, INTERFACESAFE_FOR_UNTRUSTED_CALLER, INTERFACESAFE_FOR_UNTRUSTED_CALLER); if (SUCCEEDED(hr)) { VARIANT varDir; hr = InitVariantFromIDList(&varDir, pidlFull); if (SUCCEEDED(hr)) { IObjectWithSite * pows; hr = psd->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pows)); if (SUCCEEDED(hr)) { Folder *psdf; // If we call ::SetSite(), they will display UI to ask the user if they want to allow this. // This is annoying because Trident will always call our get_item() when they load our object // tag. pows->SetSite(m_spClientSite); hr = psd->NameSpace(varDir, &psdf); if (S_OK == hr) { Folder2 *psdf2; hr = psdf->QueryInterface(IID_PPV_ARG(Folder2, &psdf2)); if (S_OK == hr) { hr = psdf2->get_Self(ppFolderItem); psdf2->Release(); } psdf->Release(); } pows->SetSite(NULL); pows->Release(); } VariantClear(&varDir); } } pos->Release(); } psd->Release(); } ILFree(pidlFull); } // Automation method can't fail or hard script error. We do want a hard // script error on access denied, however. if (FAILED(hr) && (hr != E_ACCESSDENIED)) { hr = S_FALSE; } } return hr; } STDMETHODIMP CWebViewFolderIcon::put_item(FolderItem * pFolderItem) { HRESULT hr; if (S_OK != _IsSafe()) { // 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. hr = E_ACCESSDENIED; } else { hr = S_FALSE; LPITEMIDLIST pidlNew; if (S_OK == SHGetIDListFromUnk(pFolderItem, &pidlNew)) { ATOMICRELEASE(m_pDropTargetCache); // We will want another IDropTarget for this new pidl. ILFree(m_pidl); m_pidl = pidlNew; hr = OnImageChanged(); if (FAILED(hr)) { hr = S_FALSE; } } } return hr; } STDMETHODIMP CWebViewFolderIcon::get_clickStyle(LONG *plClickStyle) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { *plClickStyle = m_clickStyle; return S_OK; } } STDMETHODIMP CWebViewFolderIcon::put_clickStyle(LONG lClickStyle) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { switch (lClickStyle) { case 1: /* oneclick - weblike */ case 2: /* twoclick - explorer-like */ m_clickStyle = lClickStyle; break; default: /* Ignore invalid arguments to keep script happy */ break; } return S_OK; } } STDMETHODIMP CWebViewFolderIcon::get_labelGap(LONG *plLabelGap) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { *plLabelGap = m_cxLabelGap; return S_OK; } } STDMETHODIMP CWebViewFolderIcon::put_labelGap(LONG lLabelGap) { if (S_OK != _IsSafe()) { return E_ACCESSDENIED; } else { if (m_cxLabelGap != lLabelGap) { m_cxLabelGap = lLabelGap; UpdateSize(); } return S_OK; } } STDMETHODIMP CWebViewFolderIcon::setSlice(int index, VARIANT varHiBytes, VARIANT varLoBytes, VARIANT varColorref) { HRESULT hr = S_FALSE; PieSlice_S pieSlice; if ((varHiBytes.vt == VT_I4) && (varLoBytes.vt == VT_I4)) pieSlice.MemSize = GetUllMemFromVars(&varHiBytes, &varLoBytes); // Passed a COLORREF if (varColorref.vt == VT_I4) { pieSlice.Color = (COLORREF)varColorref.lVal; } // Passed a string else if (varColorref.vt == VT_BSTR) pieSlice.Color = ColorRefFromHTMLColorStrW(varColorref.bstrVal); else return hr; if (DSA_SetItem(m_hdsaSlices, index, &pieSlice)) { if (index > (m_highestIndexSlice - 1)) m_highestIndexSlice = (index + 1); hr = OnImageChanged(); } return hr; } ///////////////////////////////////////////////////////////////////////////// // IObjectSafetyImpl overrides STDMETHODIMP CWebViewFolderIcon::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) { // If we're being asked to set our safe for scripting option then oblige if (riid == IID_IDispatch || riid == IID_IPersistPropertyBag) { // Store our current safety level to return in GetInterfaceSafetyOptions m_dwCurrentSafety = dwEnabledOptions & dwOptionSetMask; return S_OK; } return E_NOINTERFACE; } // Handle Window messages for the thumbnail bitmap LRESULT CALLBACK CWebViewFolderIcon::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CWebViewFolderIcon *ptc = (CWebViewFolderIcon *)::GetWindowLongPtr(hwnd, GWLP_USERDATA); switch(uMsg) { case WM_CREATE: { ptc = (CWebViewFolderIcon *)((CREATESTRUCT *)lParam)->lpCreateParams; ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)ptc); } break; // NOTE: do not need to check to see that the bitmap coming through is the one you want since each control has its own // message wnd. case WM_HTML_BITMAP: // check that ptc is still alive and that you have an HBITMAP if (ptc && (ptc->m_dwThumbnailID == wParam)) { if (ptc->m_hbm != NULL) { DeleteObject(ptc->m_hbm); } ptc->m_hbm = (HBITMAP)lParam; ptc->_InvokeOnThumbnailReady(); ptc->ForceRedraw(); } else if (lParam) { DeleteObject((HBITMAP)lParam); } break; case WM_MEASUREITEM: case WM_DRAWITEM: case WM_INITMENUPOPUP: if (ptc && ptc->m_pcm3) ptc->m_pcm3->HandleMenuMsg(uMsg, wParam, 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 CWebViewFolderIcon::ComputeFreeSpace(LPCWSTR pszFileName) { return _ComputeFreeSpace(pszFileName, m_ullFreeSpace, m_ullUsedSpace, m_ullTotalSpace); } // Draw3dPie draws the pie chart with the used slice and the additional slices in m_hdsaSlices // Look in drawpie.c for the majority of the code (including member functions called within this one) HRESULT CWebViewFolderIcon::Draw3dPie(HDC hdc, LPRECT lprc, DWORD dwPercent1000, const COLORREF *pColors) { LONG ShadowDepth; ASSERT(lprc != NULL && pColors != NULL); const LONG c_ShadowScale = 6; // ratio of shadow depth to height const LONG c_AspectRatio = 2; // ratio of width : height of ellipse ScalePieRect(c_ShadowScale, c_AspectRatio, lprc); // Compute a shadow depth based on height of the image ShadowDepth = (lprc->bottom - lprc->top) / c_ShadowScale; // Check dwPercent1000 to ensure within bounds. Shouldn't be but check anyway. // dwPercent1000 is the percentage of used space based out of 1000. if (dwPercent1000 > 1000) dwPercent1000 = 1000; // Now the drawing portion RECT rcItem; int cx, cy; // Center of the pie int rx, ry; // Center of the rectangle int x, y; // Radial intersection of the slices int FirstQuadPercent1000; // Set up the pie rectangle rcItem = *lprc; rcItem.left = lprc->left; rcItem.top = lprc->top; rcItem.right = lprc->right - rcItem.left; rcItem.bottom = lprc->bottom - rcItem.top - ShadowDepth; SetUpPiePts(&cx, &cy, &rx, &ry, rcItem); if ((rx <= 10) || (ry <= 10)) { return S_FALSE; } // Make the rectangle a little more accurate rcItem.right = (2 * rx) + rcItem.left; rcItem.bottom = (2 * ry) + rcItem.top; // Translate the used percentage to first quadrant FirstQuadPercent1000 = (dwPercent1000 % 500) - 250; if (FirstQuadPercent1000 < 0) { FirstQuadPercent1000 = -FirstQuadPercent1000; } // Find the slice intersection for the used slice CalcSlicePoint(&x, &y, rx, ry, cx, cy, FirstQuadPercent1000, dwPercent1000); DrawEllipse(hdc, rcItem, x, y, cx, cy, dwPercent1000, pColors); // Used pie slice. DrawSlice(hdc, rcItem, dwPercent1000, rx, ry, cx, cy, pColors[COLOR_UP]); // Iterate through and draw the slices in m_hdsaSlices. PieSlice_S pieSlice; ULONGLONG ullMemTotal = 0; // Keep track of memory in the m_hdsaSlices slices DWORD dwPercentTotal; // 1000 Percentage of memory in slices for (int i=0; i < m_highestIndexSlice; i++) { if (DSA_GetItemPtr(m_hdsaSlices, i) != NULL) { DSA_GetItem(m_hdsaSlices, i, &pieSlice); ullMemTotal += pieSlice.MemSize; } } ComputeSlicePct(ullMemTotal, &dwPercentTotal); if (m_highestIndexSlice) { for (i = (m_highestIndexSlice - 1); i >= 0; i--) { if (DSA_GetItemPtr(m_hdsaSlices, i)) { DSA_GetItem(m_hdsaSlices, i, &pieSlice); DrawSlice(hdc, rcItem, dwPercentTotal, rx, ry, cx, cy, pieSlice.Color); ullMemTotal -= pieSlice.MemSize; ComputeSlicePct(ullMemTotal, &dwPercentTotal); } } } DrawShadowRegions(hdc, rcItem, lprc, x, cy, ShadowDepth, dwPercent1000, pColors); DrawPieDepth(hdc, rcItem, x, y, cy, dwPercent1000, ShadowDepth); // Redraw the bottom line of the pie because it has been painted over Arc(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom, rcItem.left, cy, rcItem.right, cy); return S_OK; // Everything worked fine } void CWebViewFolderIcon::ScalePieRect(LONG ShadowScale, LONG AspectRatio, LPRECT lprc) { LONG rectHeight; LONG rectWidth; LONG TargetHeight; LONG TargetWidth; // 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 rectHeight = lprc->bottom - lprc->top; rectWidth = lprc->right - lprc->left; if ((rectHeight * AspectRatio) <= rectWidth) TargetHeight = rectHeight; else TargetHeight = rectWidth / AspectRatio; TargetWidth = TargetHeight * AspectRatio; // Shrink the rectangle to the correct size lprc->top += (rectHeight - TargetHeight) / 2; lprc->bottom = lprc->top + TargetHeight; lprc->left += (rectWidth - TargetWidth) / 2; lprc->right = lprc->left + TargetWidth; } // Calculate center of rectangle and center of pie points void CWebViewFolderIcon::SetUpPiePts(int *pcx, int *pcy, int *prx, int *pry, RECT rect) { *prx = rect.right / 2; *pcx = rect.left + *prx - 1; *pry = rect.bottom / 2; *pcy = rect.top + *pry - 1; } void CWebViewFolderIcon::DrawShadowRegions(HDC hdc, RECT rect, LPRECT lprc, int UsedArc_x, int center_y, LONG ShadowDepth, DWORD dwPercent1000, const COLORREF *pColors) { HBRUSH hBrush; HRGN hEllipticRgn = CreateEllipticRgnIndirect(&rect); HRGN hEllRect = CreateRectRgn(rect.left, center_y, rect.right, center_y + ShadowDepth); HRGN hRectRgn = CreateRectRgn(0, 0, 0, 0); // Move the ellipse up so it doesn't run into the shadow OffsetRgn(hEllipticRgn, 0, ShadowDepth); // Union the Ellipse and the Ellipse rect together into hRectRegn CombineRgn(hRectRgn, hEllipticRgn, hEllRect, RGN_OR); OffsetRgn(hEllipticRgn, 0, -(int)ShadowDepth); CombineRgn(hEllRect, hRectRgn, hEllipticRgn, RGN_DIFF); // Always draw the whole area in the free shadow hBrush = CreateSolidBrush(pColors[COLOR_DNSHADOW]); if (hBrush) { FillRgn(hdc, hEllRect, hBrush); DeleteObject(hBrush); } // Draw a shadow for the used section only if the disk is at least half used hBrush = CreateSolidBrush(pColors[COLOR_UPSHADOW]); if ((dwPercent1000 > 500) && hBrush) { DeleteObject(hRectRgn); hRectRgn = CreateRectRgn(UsedArc_x, center_y, rect.right, lprc->bottom); CombineRgn(hEllipticRgn, hEllRect, hRectRgn, RGN_AND); FillRgn(hdc, hEllipticRgn, hBrush); DeleteObject(hBrush); } DeleteObject(hRectRgn); DeleteObject(hEllipticRgn); DeleteObject(hEllRect); } void CWebViewFolderIcon::CalcSlicePoint(int *x, int *y, int rx, int ry, int cx, int cy, int FirstQuadPercent1000, DWORD dwPercent1000) { // Use a triangle area approximation based on the ellipse's rect to calculate the point since // an exact calculation of the area of the slice and percentage of the pie would be costly and // a hassle. // The approximation is better this way if FirstQuadPercent1000 is in the first half of the quadrant. Use 120 as the // halfway point (instead of 125) because it looks better that way on an ellipse. if (FirstQuadPercent1000 < 120) { *x = IntSqrt(((DWORD)rx*(DWORD)rx*(DWORD)FirstQuadPercent1000*(DWORD)FirstQuadPercent1000) /((DWORD)FirstQuadPercent1000*(DWORD)FirstQuadPercent1000+(250L-(DWORD)FirstQuadPercent1000) *(250L-(DWORD)FirstQuadPercent1000))); *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)FirstQuadPercent1000)*(250L-(DWORD)FirstQuadPercent1000) /((DWORD)FirstQuadPercent1000*(DWORD)FirstQuadPercent1000+(250L-(DWORD)FirstQuadPercent1000) *(250L-(DWORD)FirstQuadPercent1000))); *x = IntSqrt(((DWORD)ry*(DWORD)ry-(DWORD)(*y)*(DWORD)(*y))*(DWORD)rx*(DWORD)rx/((DWORD)ry*(DWORD)ry)); } // Adjust for the actual quadrant (These aren't quadrants like in the real Cartesian coordinate system. switch (dwPercent1000 / 250) { case 1: // First Quadrant *y = -(*y); break; case 2: // Second Quadrant break; case 3: // Third Quadrant *x = -(*x); break; default: // Fourth Quadrant *x = -(*x); *y = -(*y); break; } // Now adjust for the center. *x += cx; *y += cy; } void CWebViewFolderIcon::ComputeSlicePct(ULONGLONG ullMemSize, DWORD *pdwPercent1000) { // some special cases require interesting treatment if ((ullMemSize == 0) || (m_ullFreeSpace == m_ullTotalSpace)) { *pdwPercent1000 = 0; } else if (ullMemSize == 0) { *pdwPercent1000 = 1000; } else { // not completely full or empty *pdwPercent1000 = (DWORD)(ullMemSize * 1000 / m_ullTotalSpace); // if pdwPercent1000 is especially big or small and rounds incorrectly, you still want // to see a little slice. if (*pdwPercent1000 == 0) { *pdwPercent1000 = 1; } else if (*pdwPercent1000 == 1000) { *pdwPercent1000 = 999; } } } void CWebViewFolderIcon::DrawPieDepth(HDC hdc, RECT rect, int x, int y, int cy, DWORD dwPercent1000, LONG ShadowDepth) { HPEN hPen, hOldPen; hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME)); hOldPen = (HPEN__*) SelectObject(hdc, hPen); Arc(hdc, rect.left, rect.top + ShadowDepth, rect.right, rect.bottom + ShadowDepth, rect.left, cy + ShadowDepth, rect.right, cy + ShadowDepth - 1); MoveToEx(hdc, rect.left, cy, NULL); LineTo(hdc, rect.left, cy + ShadowDepth); MoveToEx(hdc, rect.right - 1, cy, NULL); LineTo(hdc, rect.right - 1, cy + ShadowDepth); if ((dwPercent1000 > 500) && (dwPercent1000 < 1000)) { MoveToEx(hdc, x, y, NULL); LineTo(hdc, x, y + ShadowDepth); } SelectObject(hdc, hOldPen); DeleteObject(hPen); } // Draw a pie slice. One side is always from the middle of the pie horizontally to the left. The other // slice is defined by x and y. void CWebViewFolderIcon::DrawSlice(HDC hdc, RECT rect, DWORD dwPercent1000, int rx, int ry, int cx, int cy, /*int *px, int *py,*/ COLORREF Color) { HBRUSH hBrush, hOldBrush; HPEN hPen, hOldPen; int FirstQuadPercent1000; // slice percentage based out of 1000 in the first quadrant int x, y; // intersection with the ellipse // Translate to first quadrant FirstQuadPercent1000 = (dwPercent1000 % 500) - 250; if (FirstQuadPercent1000 < 0) { FirstQuadPercent1000 = -FirstQuadPercent1000; } CalcSlicePoint(&x, &y, rx, ry, cx, cy, FirstQuadPercent1000, dwPercent1000); hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME)); hOldPen = (HPEN__*) SelectObject(hdc, hPen); if ((dwPercent1000 != 0) && (dwPercent1000 != 1000)) { // display small sub-section of ellipse for smaller part hBrush = CreateSolidBrush(Color); hOldBrush = (HBRUSH__*) SelectObject(hdc, hBrush); // Make sure it colors correctly if (cy == y) { if (dwPercent1000 < 500) y--; else y++; } Pie(hdc, rect.left, rect.top, rect.right, rect.bottom, x, y, rect.left, cy); SelectObject(hdc, hOldBrush); DeleteObject(hBrush); } SelectObject(hdc, hOldPen); DeleteObject(hPen); } void CWebViewFolderIcon::DrawEllipse(HDC hdc, RECT rect, int x, int y, int cx, int cy, DWORD dwPercent1000, const COLORREF *pColors) { HBRUSH hBrush, hOldBrush; HPEN hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME)); HPEN hOldPen = (HPEN__*) SelectObject(hdc, hPen); // In this case the slice is miniscule if ((dwPercent1000 < 500) && (y == cy) && (x < cx)) { hBrush = CreateSolidBrush(pColors[COLOR_UP]); } else { hBrush = CreateSolidBrush(pColors[COLOR_DN]); } hOldBrush = (HBRUSH__*) SelectObject(hdc, hBrush); Ellipse(hdc, rect.left, rect.top, rect.right, rect.bottom); SelectObject(hdc, hOldBrush); DeleteObject(hBrush); SelectObject(hdc, hOldPen); DeleteObject(hPen); }