From e1895f945d5b65a39e1a3dda62c3234e9c250051 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 14 Aug 2010 00:45:15 +0200 Subject: [PATCH 001/207] AERO for VISTA --- Console/AboutDlg.cpp | 9 +- Console/AboutDlg.h | 10 +- Console/AeroTabCtrl.h | 531 ++++++++++ Console/Console.cpp | 12 + Console/Console.rc | 77 +- Console/Console.vcproj | 220 ++++- Console/ConsoleView.cpp | 11 +- Console/DlgRenameTab.cpp | 8 + Console/DlgRenameTab.h | 7 + Console/DlgSettingsStyles.h | 2 +- Console/ImageHandler.cpp | 2 +- Console/MainFrame.cpp | 298 +++--- Console/MainFrame.h | 7 + Console/SelectionHandler.h | 2 +- Console/SettingsHandler.h | 11 +- Console/res/toolbar_aero.bmp | Bin 0 -> 7222 bytes Console/resource.h | 14 +- Console/stdafx.h | 26 +- Console/wtlaero.h | 1584 ++++++++++++++++++++++++++++++ Console2.sln | 10 + ConsoleHook/ConsoleHook.vcproj | 173 +++- TabbingFramework/CustomTabCtrl.h | 44 +- TabbingFramework/DotNetTabCtrl.h | 10 +- TabbingFramework/TabbedFrame.h | 8 +- 24 files changed, 2838 insertions(+), 238 deletions(-) create mode 100644 Console/AeroTabCtrl.h create mode 100644 Console/res/toolbar_aero.bmp create mode 100644 Console/wtlaero.h diff --git a/Console/AboutDlg.cpp b/Console/AboutDlg.cpp index 1d3e6968..2ce84d52 100644 --- a/Console/AboutDlg.cpp +++ b/Console/AboutDlg.cpp @@ -12,10 +12,17 @@ LRESULT CAboutDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPara CWindow staticMessage(GetDlgItem(IDC_STATIC_VERSION)); CString strMsg; - strMsg.Format(L"Console %i.%02i.%i", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); + strMsg.Format(L"\nConsole %i.%02i.%i\n", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); staticMessage.SetWindowText(strMsg); CenterWindow(GetParent()); + +#ifdef _USE_AERO + AERO_CONTROL(CButton, m_Ok, IDOK) + AERO_CONTROL(CStatic, m_Version, IDC_STATIC_VERSION) + AERO_CONTROL(CStatic, m_Text, IDC_APPTEXT) +#endif + return TRUE; } diff --git a/Console/AboutDlg.h b/Console/AboutDlg.h index c7276585..0f6eaea3 100644 --- a/Console/AboutDlg.h +++ b/Console/AboutDlg.h @@ -4,12 +4,20 @@ #pragma once -class CAboutDlg : public CDialogImpl +class CAboutDlg : +#ifdef _USE_AERO + public aero::CDialogImpl +#else + public CDialogImpl +#endif { public: enum { IDD = IDD_ABOUTBOX }; BEGIN_MSG_MAP(CAboutDlg) +#ifdef _USE_AERO + CHAIN_MSG_MAP(aero::CDialogImpl) +#endif MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_ID_HANDLER(IDOK, OnCloseCmd) COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) diff --git a/Console/AeroTabCtrl.h b/Console/AeroTabCtrl.h new file mode 100644 index 00000000..2fd644f0 --- /dev/null +++ b/Console/AeroTabCtrl.h @@ -0,0 +1,531 @@ +#pragma once + +template +class CAeroTabCtrlImpl : + public CDotNetTabCtrlImpl +{ +protected: + typedef CAeroTabCtrlImpl thisClass; + typedef CDotNetTabCtrlImpl baseClass; + + signed char m_iMargin; + signed char m_iLeftSpacing; + signed char m_iTopMargin; + signed char m_iRadius; + +// Constructor +public: + + CAeroTabCtrlImpl() + { + // We can't use a member initialization list to initialize + // members of our base class, so do it explictly by assignment here. + m_clrTextInactiveTab = /*RGB(255,255,255); */::GetSysColor(COLOR_BTNTEXT); + m_clrSelectedTab = ::GetSysColor(COLOR_WINDOW); + } + +// Message Handling +public: + DECLARE_WND_CLASS_EX(_T("WTL_CAeroTabCtrl"), CS_DBLCLKS, COLOR_WINDOW) + + BEGIN_MSG_MAP(thisClass) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSettingChange) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + DWORD dwStyle = this->GetStyle(); + + // Initialize/Reinitialize font + // Visual Studio.Net seems to use the "icon" font for the tabs + LOGFONT lfIcon = { 0 }; + ::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIcon), &lfIcon, 0); + + bool bResetFont = true; + if(!m_font.IsNull()) + { + LOGFONT lf = {0}; + if(m_font.GetLogFont(&lf)) + { + if(lstrcmpi(lf.lfFaceName, lfIcon.lfFaceName) == 0 && + lf.lfHeight == lfIcon.lfHeight) + { + bResetFont = false; + } + } + } + + if(bResetFont) + { + if(!m_font.IsNull()) m_font.DeleteObject(); + if(!m_fontSel.IsNull()) m_fontSel.DeleteObject(); + + HFONT font = m_font.CreateFontIndirect(&lfIcon); + if(font==NULL) + { + m_font.Attach(AtlGetDefaultGuiFont()); + } + + if(CTCS_BOLDSELECTEDTAB == (dwStyle & CTCS_BOLDSELECTEDTAB)) + { + lfIcon.lfWeight = FW_BOLD; + } + + font = m_fontSel.CreateFontIndirect(&lfIcon); + if(font==NULL) + { + m_fontSel.Attach(AtlGetDefaultGuiFont()); + } + } + + // Background brush + if(!m_hbrBackground.IsNull() ) m_hbrBackground.DeleteObject(); + + m_hbrBackground.CreateSysColorBrush(COLOR_BTNFACE); + + m_iMargin = 6; + m_iLeftSpacing = 2; + m_iTopMargin = 4; + m_iRadius = 3; + m_settings.iIndent = 5; + m_settings.iPadding = 4; + m_settings.iMargin = m_iMargin + m_iLeftSpacing / 2; + m_settings.iSelMargin = 6; + + T* pT = static_cast(this); + pT->UpdateLayout(); + pT->Invalidate(); + return 0; + } + +// Overrides for painting from CDotNetTabCtrlImpl +public: + + void DrawBackground(RECT /*rcClient*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw) + { + Gdiplus::Graphics g(lpNMCustomDraw->nmcd.hdc); + g.Clear(Gdiplus::Color(0,0,0,0)); + } + + void DrawTab(RECT& rcTab, Gdiplus::Graphics& g, Gdiplus::Color& color) + { + Gdiplus::SolidBrush brush(color); + + Gdiplus::GraphicsPath gp; + + INT radius = m_iRadius; + INT X = rcTab.left + m_iLeftSpacing; + INT Y = rcTab.top + m_iTopMargin; + INT width = rcTab.right - rcTab.left - m_iLeftSpacing - 2; + INT height = rcTab.bottom - rcTab.top - m_iTopMargin; + + /* + gp.AddLine(X + radius, Y, X + width - (radius * 2), Y); + gp.AddArc(X + width - (radius * 2), Y, radius * 2, radius * 2, 270, 90); + gp.AddLine(X + width, Y + radius, X + width, Y + height); + gp.AddLine(X + width, Y + height, X, Y + height); + gp.AddLine(X, Y + height, X, Y + radius); + gp.AddArc(X, Y, radius * 2, radius * 2, 180, 90); + */ + gp.AddLine(X + radius, Y, X + width - radius, Y); + gp.AddLine(X + width - radius, Y, X + width, Y + radius); + gp.AddLine(X + width, Y + radius, X + width, Y + height); + gp.AddLine(X + width, Y + height, X, Y + height); + gp.AddLine(X, Y + height, X, Y + radius); + gp.AddLine(X, Y + radius, X + radius, Y); + + g.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); + Gdiplus::Pen pen(color,1.0); + g.DrawPath(&pen, &gp); + + g.SetSmoothingMode(Gdiplus::SmoothingModeNone); + g.FillPath(&brush, &gp); + + radius += 2; + X -= 1; + Y -= 1; + width += 2; + height += 2; + + g.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); + Gdiplus::Pen pen2(Gdiplus::Color(64, 0, 0,0),1.0); + + g.DrawLine(&pen2, X, Y + radius, X + radius, Y); + g.DrawLine(&pen2, X, Y + height, X, Y + radius); + g.DrawLine(&pen2, X + radius, Y, X + width - radius, Y); + g.DrawLine(&pen2, X + width - radius, Y, X + width, Y + radius); + g.DrawLine(&pen2, X + width, Y + radius, X + width, Y + height); + } + + void DrawItem_InitBounds(DWORD /*dwStyle*/, RECT /*rcItem*/, RECT& rcTab, RECT& rcText, int& nIconVerticalCenter) + { + rcText.top += m_iTopMargin; + rcText.left += (m_iLeftSpacing + m_iMargin); + rcText.right -= m_iMargin; + nIconVerticalCenter = (rcTab.bottom + rcTab.top - m_iTopMargin) / 2 + m_iTopMargin; + } + + void DrawItem_TabInactive(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw, RECT& rcTab) + { + } + + void DrawItem_TabSelected(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw, RECT& rcTab) + { + } + + void DrawItem_ImageAndText(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw, int nIconVerticalCenter, RECT& rcTab, RECT& rcText) + { + HDC targetDC = lpNMCustomDraw->nmcd.hdc; + HDC bufferedDC = NULL; + BP_PAINTPARAMS m_PaintParams = { sizeof(BP_PAINTPARAMS) }; + HPAINTBUFFER pb = BeginBufferedPaint(targetDC, &rcTab, BPBF_TOPDOWNDIB, &m_PaintParams, &bufferedDC); + BufferedPaintClear(pb, &rcTab); + Gdiplus::Graphics g(bufferedDC); + + bool bHighlighted = (CDIS_MARKED == (lpNMCustomDraw->nmcd.uItemState & CDIS_MARKED)); + bool bSelected = (CDIS_SELECTED == (lpNMCustomDraw->nmcd.uItemState & CDIS_SELECTED)); + bool bHot = (CDIS_HOT == (lpNMCustomDraw->nmcd.uItemState & CDIS_HOT)); + int nItem = (int)lpNMCustomDraw->nmcd.dwItemSpec; + + TItem* pItem = this->GetItem(nItem); + + ::SelectObject( + bufferedDC, + ( bSelected )? + lpNMCustomDraw->hFontSelected : + lpNMCustomDraw->hFontInactive); + + COLORREF txtcolorref = 0; + COLORREF tabcolorref = 0; + BYTE byteAlpha = 0; + if(bSelected) + { + txtcolorref = lpNMCustomDraw->clrTextSelected; + tabcolorref = lpNMCustomDraw->clrSelectedTab; + byteAlpha = 255; + } + else if(bHighlighted) + { + txtcolorref = lpNMCustomDraw->clrHighlightText; + if( bHot ) + { + tabcolorref = lpNMCustomDraw->clrHighlightHotTrack; + byteAlpha = 96; + } + else + { + tabcolorref = lpNMCustomDraw->clrHighlight; + byteAlpha = 64; + } + } + else if(bHot) + { + txtcolorref = lpNMCustomDraw->clrTextInactive; + tabcolorref = lpNMCustomDraw->clrSelectedTab; + byteAlpha = 96; + } + else + { + txtcolorref = lpNMCustomDraw->clrTextInactive; + tabcolorref = lpNMCustomDraw->clrSelectedTab; + byteAlpha = 64; + } + Gdiplus::Color tabcolor; + tabcolor.SetFromCOLORREF(tabcolorref); + tabcolor.SetValue(Gdiplus::Color::MakeARGB(byteAlpha, tabcolor.GetR(), tabcolor.GetG(), tabcolor.GetB())); + + this->DrawTab(rcTab, g, tabcolor); + + //-------------------------------------------- + // This is how CDotNetTabCtrlImpl interprets padding, margin, etc.: + // + // M - Margin + // P - Padding + // I - Image + // Text - Tab Text + // + // With image: + // __________________________ + // + // | M | I | P | Text | P | M | + // -------------------------- + // + // Without image: + // ______________________ + // + // | M | P | Text | P | M | + // ---------------------- + + if (pItem->UsingImage() && !m_imageList.IsNull()) + { + // Draw the image. + IMAGEINFO ii = {0}; + int nImageIndex = pItem->GetImageIndex(); + m_imageList.GetImageInfo(nImageIndex, &ii); + + if((ii.rcImage.right - ii.rcImage.left) < (rcTab.right - rcTab.left)) + { + int nImageHalfHeight = (ii.rcImage.bottom - ii.rcImage.top) / 2; + CIcon icon; + icon.Attach(m_imageList.ExtractIcon(nImageIndex)); + Gdiplus::Bitmap bitmap(icon.m_hIcon); + + g.DrawImage( + &bitmap, + rcText.left, + nIconVerticalCenter - nImageHalfHeight + m_nFontSizeTextTopOffset); + } + + // Offset on the right of the image. + rcText.left += (ii.rcImage.right - ii.rcImage.left); + } + + if (rcText.left + m_nMinWidthToDisplayText < rcText.right) + { + ::InflateRect(&rcText, -m_settings.iPadding, 0); + + TCHAR szTitle[256]; + int szTitleLen = _sntprintf_s(szTitle, 256, _TRUNCATE, _T("%d. %s"), nItem + 1, pItem->GetText()); + + bool bGlow = true; + + DTTOPTS dtto = { 0 }; + dtto.dwSize = sizeof(DTTOPTS); + dtto.iGlowSize = 8; + dtto.crText = txtcolorref; + dtto.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE; + + HTHEME hTheme = OpenThemeData(m_hWnd, VSCLASS_WINDOW); + + DrawThemeTextEx( + hTheme, + bufferedDC, + WP_CAPTION, CS_ACTIVE, + szTitle, + szTitleLen, + DT_PATH_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX, + &rcText, + &dtto); + + CloseThemeData(hTheme); + } + + EndBufferedPaint(pb, TRUE); + } + + void DrawCloseButton(LPNMCTCCUSTOMDRAW lpNMCustomDraw) + { + RECT zone; + zone.top = min(m_rcScrollLeft.top, m_rcCloseButton.top); + zone.left = m_rcScrollLeft.left; + zone.bottom = max(m_rcScrollLeft.bottom, m_rcCloseButton.bottom); + zone.right = m_rcCloseButton.right; + + HDC targetDC = lpNMCustomDraw->nmcd.hdc; + HDC bufferedDC = NULL; + BP_PAINTPARAMS m_PaintParams = { sizeof(BP_PAINTPARAMS) }; + HPAINTBUFFER pb = BeginBufferedPaint(targetDC, &zone, BPBF_TOPDOWNDIB, &m_PaintParams, &bufferedDC); + BufferedPaintClear(pb, &zone); + + int iStateCloseButton = CBS_NORMAL; + if( ectcMouseDownL_CloseButton == (m_dwState & ectcMouseDown) ) + iStateCloseButton = CBS_PUSHED; + else if( ectcMouseOver_CloseButton == (m_dwState & ectcMouseOver) ) + iStateCloseButton = CBS_HOT; + + HTHEME hTheme = OpenThemeData(m_hWnd, VSCLASS_WINDOW); + + DrawThemeBackgroundEx( + hTheme, + bufferedDC, + WP_SMALLCLOSEBUTTON, + iStateCloseButton, + &m_rcCloseButton, + NULL); + + CloseThemeData(hTheme); + + int iStateScrollLeft = NAV_BB_DISABLED; + if( m_dwState & ectcOverflowLeft ) + { + iStateScrollLeft = NAV_BB_NORMAL; + if( ectcMouseDownL_ScrollLeft == (m_dwState & ectcMouseDown) ) + iStateScrollLeft = NAV_BB_PRESSED; + else if( ectcMouseOver_ScrollLeft == (m_dwState & ectcMouseOver) ) + iStateScrollLeft = NAV_BB_HOT; + } + + int iStateScrollRight = NAV_BB_DISABLED; + if( m_dwState & ectcOverflowRight ) + { + iStateScrollRight = NAV_FB_NORMAL; + if( ectcMouseDownL_ScrollRight == (m_dwState & ectcMouseDown) ) + iStateScrollRight = NAV_FB_PRESSED; + else if( ectcMouseOver_ScrollRight == (m_dwState & ectcMouseOver) ) + iStateScrollRight = NAV_FB_HOT; + } + + hTheme = OpenThemeData(m_hWnd, VSCLASS_NAVIGATION); + + DrawThemeBackgroundEx( + hTheme, + bufferedDC, + NAV_BACKBUTTON, + iStateScrollLeft, + &m_rcScrollLeft, + NULL); + + DrawThemeBackgroundEx( + hTheme, + bufferedDC, + NAV_FORWARDBUTTON, + iStateScrollRight, + &m_rcScrollRight, + NULL); + + CloseThemeData(hTheme); + + EndBufferedPaint(pb, TRUE); + } + + void DrawScrollButtons(LPNMCTCCUSTOMDRAW lpNMCustomDraw) + { + } + + void CalcSize_CloseButton(LPRECT prcTabItemArea) + { + SIZE size; + + HTHEME hTheme = OpenThemeData(m_hWnd, VSCLASS_WINDOW); + + GetThemePartSize( + hTheme, + NULL, + WP_SMALLCLOSEBUTTON, + 0, + NULL, + TS_TRUE, + &size + ); + + CloseThemeData(hTheme); + + if( (prcTabItemArea->right - prcTabItemArea->left) < size.cx ) + { + ::SetRectEmpty(&m_rcCloseButton); + return; + } + + m_rcCloseButton = *prcTabItemArea; + + DWORD dwStyle = this->GetStyle(); + + if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) + { + m_rcCloseButton.top += 3; + } + else + { + m_rcCloseButton.top += 1; + m_rcCloseButton.bottom -= 2; + } + m_rcCloseButton.top = (m_rcCloseButton.bottom + m_rcCloseButton.top - size.cy) / 2; + m_rcCloseButton.bottom = m_rcCloseButton.top + size.cy; + + m_rcCloseButton.left = m_rcCloseButton.right - (size.cx); + + if(m_tooltip.IsWindow()) + { + m_tooltip.SetToolRect(m_hWnd, (UINT)ectcToolTip_Close, &m_rcCloseButton); + } + + // Adjust the tab area + prcTabItemArea->right = m_rcCloseButton.left - 3; + } + + void CalcSize_ScrollButtons(LPRECT prcTabItemArea) + { + SIZE size; + + HTHEME hTheme = OpenThemeData(m_hWnd, VSCLASS_NAVIGATION); + + GetThemePartSize( + hTheme, + NULL, + NAV_BACKBUTTON, + 0, + NULL, + TS_TRUE, + &size + ); + + CloseThemeData(hTheme); + + if((prcTabItemArea->right - prcTabItemArea->left) < size.cx) + { + ::SetRectEmpty(&m_rcScrollRight); + ::SetRectEmpty(&m_rcScrollLeft); + return; + } + + RECT rcScroll = *prcTabItemArea; + + DWORD dwStyle = this->GetStyle(); + + if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) + { + rcScroll.top += 3; + } + else + { + rcScroll.top += 1; + rcScroll.bottom -= 2; + } + rcScroll.top = (rcScroll.bottom + rcScroll.top - size.cy) / 2; + rcScroll.bottom = rcScroll.top + size.cy; + + m_rcScrollRight = rcScroll; + m_rcScrollLeft = rcScroll; + + m_rcScrollRight.left = m_rcScrollRight.right - size.cx; + + m_rcScrollLeft.right = m_rcScrollRight.left - 3; + m_rcScrollLeft.left = m_rcScrollLeft.right - size.cx; + + if(m_tooltip.IsWindow()) + { + m_tooltip.SetToolRect(m_hWnd, (UINT)ectcToolTip_ScrollRight, &m_rcScrollRight); + m_tooltip.SetToolRect(m_hWnd, (UINT)ectcToolTip_ScrollLeft, &m_rcScrollLeft); + } + + // Adjust the tab area + prcTabItemArea->right = m_rcScrollLeft.left; + } + +}; + +template +class CAeroTabCtrl : + public CAeroTabCtrlImpl, TItem> +{ +protected: + typedef CAeroTabCtrl thisClass; + typedef CAeroTabCtrlImpl, TItem> baseClass; + +// Constructors: +public: + CAeroTabCtrl() + { + } + +public: + + DECLARE_WND_CLASS_EX(_T("WTL_CAeroTabCtrl"), CS_DBLCLKS, COLOR_WINDOW) + + //We have nothing special to add. + //BEGIN_MSG_MAP(thisClass) + // CHAIN_MSG_MAP(baseClass) + //END_MSG_MAP() +}; \ No newline at end of file diff --git a/Console/Console.cpp b/Console/Console.cpp index af206465..dd56df74 100644 --- a/Console/Console.cpp +++ b/Console/Console.cpp @@ -219,6 +219,13 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lp // HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED); ATLASSERT(SUCCEEDED(hRes)); +#ifdef _USE_AERO + // init GDI+ + ULONG_PTR gdiplusToken; + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); +#endif + g_settingsHandler.reset(new SettingsHandler()); g_imageHandler.reset(new ImageHandler()); @@ -232,6 +239,11 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lp int nRet = Run(lpstrCmdLine, nCmdShow); +#ifdef _USE_AERO + // shutdown GDI+; + Gdiplus::GdiplusShutdown(gdiplusToken); +#endif + _Module.Term(); g_settingsHandler.reset(); diff --git a/Console/Console.rc b/Console/Console.rc index da1ad13a..b7ec9557 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -90,8 +90,11 @@ END // // Bitmap // - +#ifdef _USE_AERO +IDR_MAINFRAME BITMAP "res\\toolbar_aero.bmp" +#else IDR_MAINFRAME BITMAP "res\\Toolbar.bmp" +#endif ///////////////////////////////////////////////////////////////////////////// // @@ -181,27 +184,27 @@ END // Dialog // -IDD_ABOUTBOX DIALOGEX 0, 0, 187, 102 +IDD_ABOUTBOX DIALOGEX 0, 0, 187, 131 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - DEFPUSHBUTTON "OK",IDOK,130,81,50,14 - CTEXT "Console 2.0",IDC_STATIC_VERSION,25,56,78,8,0,WS_EX_ACCEPTFILES - ICON IDR_MAINFRAME,IDC_STATIC,55,26,20,20 - GROUPBOX "",IDC_STATIC,7,7,115,88 - CTEXT "Copyright (C) 2001-2010\nMarko Bozikovic",IDC_STATIC,25,71,78,17 + DEFPUSHBUTTON "OK",IDOK,130,110,50,14 + CTEXT "\nConsole 2.0",IDC_STATIC_VERSION,25,41,78,25,0,WS_EX_ACCEPTFILES + ICON IDR_MAINFRAME,IDC_APPICON,55,26,20,20 + GROUPBOX "",IDC_STATIC,7,7,115,117 + CTEXT "\nCopyright (C) 2001-2010\nMarko Bozikovic\n\nModified by\nChristophe Bucher",IDC_APPTEXT,14,64,103,53 END -IDD_RENAME_TAB DIALOGEX 0, 0, 186, 55 +IDD_RENAME_TAB DIALOGEX 0, 0, 202, 55 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Rename Tab" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "&New tab name:",IDC_STATIC,7,11,50,8 - EDITTEXT IDC_TAB_NAME,58,8,121,14,ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,74,34,50,14 - PUSHBUTTON "Cancel",IDCANCEL,129,34,50,14 + CTEXT "\n&New tab name:",IDC_STATIC,7,2,58,22 + EDITTEXT IDC_TAB_NAME,65,8,130,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,87,34,50,14 + PUSHBUTTON "Cancel",IDCANCEL,145,34,50,14 END IDD_SETTINGS_MAIN DIALOGEX 0, 0, 354, 321 @@ -360,7 +363,7 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,240,101,10 END -IDD_SETTINGS_STYLES DIALOGEX 0, 0, 226, 265 +IDD_SETTINGS_STYLES DIALOGEX 0, 0, 226, 276 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN @@ -370,8 +373,7 @@ BEGIN CONTROL "Show t&abs",IDC_CHECK_SHOW_TABS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,48,49,10 CONTROL "Hide &single tab",IDC_CHECK_HIDE_SINGLE_TAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,60,59,10 CONTROL "Show scro&llbars",IDC_CHECK_SHOW_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,73,72,10 - CONTROL "&Flat scrollbars",IDC_CHECK_FLAT_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,85,59,10 - GROUPBOX "Controls",IDC_STATIC,0,0,88,98 + GROUPBOX "Controls",IDC_STATIC,0,0,88,92 CONTROL "&Caption *",IDC_CHECK_STYLE_CAPTION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,12,47,10 CONTROL "Resi&zable *",IDC_CHECK_STYLE_RESIZABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,24,52,10 CONTROL "Bo&rder *",IDC_CHECK_STYLE_BORDER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,36,43,10 @@ -382,19 +384,20 @@ BEGIN CONTROL "",IDC_SPIN_INSIDE_BORDER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,191,50,11,14 LTEXT "Selection col&or:",IDC_STATIC,102,74,50,8 CONTROL "",IDC_SELECTION_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,153,71,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Styles",IDC_STATIC,92,0,134,98 - CONTROL "&None",IDC_TRANSPARENCY_TYPE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,8,114,33,10 - CONTROL "&Alpha",IDC_TRANSPARENCY_TYPE2,"Button",BS_AUTORADIOBUTTON,8,129,34,10 - CONTROL "Color &key",IDC_TRANSPARENCY_TYPE3,"Button",BS_AUTORADIOBUTTON,8,218,46,10 - LTEXT "A&ctive window",IDC_STATIC_ACTIVE_WINDOW,19,142,47,8 - CONTROL "",IDC_ACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,153,185,22 - LTEXT "255",IDC_STATIC_ACTIVE_ALPHA,204,155,14,8,0,WS_EX_RIGHT - LTEXT "&Inactive window",IDC_STATIC_INACTIVE_WINDOW,19,177,53,8 - CONTROL "",IDC_INACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,190,185,22 - LTEXT "255",IDC_STATIC_INACTIVE_ALPHA,204,192,14,8,0,WS_EX_RIGHT - LTEXT "Key col&or:",IDC_STATIC_KEY_COLOR,19,235,33,8 - CONTROL "",IDC_KEY_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,54,232,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Window transparency",IDC_STATIC,0,98,226,162 + GROUPBOX "Styles",IDC_STATIC,92,0,134,92 + CONTROL "&None",IDC_TRANSPARENCY_TYPE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,10,105,33,10 + CONTROL "&Alpha",IDC_TRANSPARENCY_TYPE2,"Button",BS_AUTORADIOBUTTON,10,120,34,10 + CONTROL "Color &key",IDC_TRANSPARENCY_TYPE3,"Button",BS_AUTORADIOBUTTON,10,212,46,10 + CONTROL "Glass",IDC_TRANSPARENCY_TYPE4,"Button",BS_AUTORADIOBUTTON,50,120,33,10 + LTEXT "A&ctive window",IDC_STATIC_ACTIVE_WINDOW,19,134,47,8 + CONTROL "",IDC_ACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,145,185,22 + LTEXT "255",IDC_STATIC_ACTIVE_ALPHA,204,147,14,8,0,WS_EX_RIGHT + LTEXT "&Inactive window",IDC_STATIC_INACTIVE_WINDOW,19,169,53,8 + CONTROL "",IDC_INACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,182,185,22 + LTEXT "255",IDC_STATIC_INACTIVE_ALPHA,204,184,14,8,0,WS_EX_RIGHT + LTEXT "Key col&or:",IDC_STATIC_KEY_COLOR,19,227,33,8 + CONTROL "",IDC_KEY_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,54,224,16,14,WS_EX_DLGMODALFRAME + GROUPBOX "Window transparency",IDC_STATIC,0,95,226,160 END IDD_SETTINGS_TEMP DIALOGEX 0, 0, 611, 555 @@ -545,15 +548,15 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 180 TOPMARGIN, 7 - BOTTOMMARGIN, 95 + BOTTOMMARGIN, 124 END IDD_RENAME_TAB, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 179 - VERTGUIDE, 58 - TOPMARGIN, 7 + RIGHTMARGIN, 195 + VERTGUIDE, 65 + TOPMARGIN, 2 BOTTOMMARGIN, 48 HORZGUIDE, 15 END @@ -846,8 +849,11 @@ END STRINGTABLE BEGIN - ID_VIEW_TOOLBAR "Show or hide the toolbar\nToggle ToolBar" - ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar" + ID_VIEW_CONSOLE "Show or hide the console" + ID_VIEW_MENU "Show or hide the menu" + ID_VIEW_TOOLBAR "Show or hide the toolbar" + ID_VIEW_STATUS_BAR "Show or hide the status bar" + ID_VIEW_TABS "Show or hide the status tabs" END STRINGTABLE @@ -904,7 +910,8 @@ END // // Generated from the TEXTINCLUDE 3 resource. // - + + ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/Console/Console.vcproj b/Console/Console.vcproj index 73a67326..72d00494 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -511,6 +689,22 @@ UsePrecompiledHeader="1" /> + + + + + + + + @@ -641,6 +839,10 @@ RelativePath="..\shared\Structures.h" > + + @@ -650,6 +852,18 @@ Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest" > + + + + + + @@ -662,6 +876,10 @@ RelativePath=".\res\toolbar.bmp" > + + UpdateSelection(GetConsoleCoord(point), m_screenBuffer); + COORD coordStart; + COORD coordEnd; + m_selectionHandler->GetSelectionCoordinates(coordStart, coordEnd); + int iSelextedSize = (coordEnd.Y - coordStart.Y) * m_consoleHandler.GetConsoleParams()->dwColumns + + (coordEnd.X - coordStart.X) + 1; + TCHAR szBuff[128]; + _sntprintf(szBuff, sizeof(szBuff), _T("[%i]"), iSelextedSize); + m_mainFrame.UISetText(1, szBuff); + m_mainFrame.UIUpdateStatusBar(); } BitBltOffscreen(); diff --git a/Console/DlgRenameTab.cpp b/Console/DlgRenameTab.cpp index 3e231082..ef118450 100644 --- a/Console/DlgRenameTab.cpp +++ b/Console/DlgRenameTab.cpp @@ -31,6 +31,14 @@ DlgRenameTab::DlgRenameTab(const CString& strTabName) LRESULT DlgRenameTab::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { DoDataExchange(DDX_LOAD); + +#ifdef _USE_AERO + AERO_CONTROL(CEdit, m_Edit, IDC_TAB_NAME) + AERO_CONTROL(CButton, m_Cancel, IDCANCEL) + AERO_CONTROL(CStatic, m_Label, IDC_STATIC) + AERO_CONTROL(CButton, m_Ok, IDOK) +#endif + return TRUE; } diff --git a/Console/DlgRenameTab.h b/Console/DlgRenameTab.h index 91700ab4..91bec3d4 100644 --- a/Console/DlgRenameTab.h +++ b/Console/DlgRenameTab.h @@ -12,7 +12,11 @@ ////////////////////////////////////////////////////////////////////////////// class DlgRenameTab +#ifdef _USE_AERO + : public aero::CDialogImpl +#else : public CDialogImpl +#endif , public CWinDataExchange { @@ -26,6 +30,9 @@ class DlgRenameTab END_DDX_MAP() BEGIN_MSG_MAP(DlgRenameTab) +#ifdef _USE_AERO + CHAIN_MSG_MAP(aero::CDialogImpl) +#endif MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_ID_HANDLER(IDOK, OnCloseCmd) COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) diff --git a/Console/DlgSettingsStyles.h b/Console/DlgSettingsStyles.h index b12ab56c..a719041f 100644 --- a/Console/DlgSettingsStyles.h +++ b/Console/DlgSettingsStyles.h @@ -46,7 +46,7 @@ class DlgSettingsStyles COMMAND_HANDLER(IDC_CHECK_SHOW_TABS, BN_CLICKED, OnClickedShowTabs) COMMAND_HANDLER(IDC_KEY_COLOR, BN_CLICKED, OnClickedKeyColor) COMMAND_HANDLER(IDC_SELECTION_COLOR, BN_CLICKED, OnClickedSelColor) - COMMAND_RANGE_CODE_HANDLER(IDC_TRANSPARENCY_TYPE, IDC_TRANSPARENCY_TYPE3, BN_CLICKED, OnClickedTransType) + COMMAND_RANGE_CODE_HANDLER(IDC_TRANSPARENCY_TYPE, IDC_TRANSPARENCY_TYPE4, BN_CLICKED, OnClickedTransType) END_MSG_MAP() // Handler prototypes (uncomment arguments if needed): diff --git a/Console/ImageHandler.cpp b/Console/ImageHandler.cpp index f1557086..780fb552 100644 --- a/Console/ImageHandler.cpp +++ b/Console/ImageHandler.cpp @@ -231,7 +231,7 @@ bool ImageHandler::LoadImage(shared_ptr& bkImage) bkImage->dwOriginalImageWidth = bkImage->originalImage->getWidth(); bkImage->dwOriginalImageHeight = bkImage->originalImage->getHeight(); - bkImage->originalImage->convertTo24Bits(); + bkImage->originalImage->convertTo32Bits(); return true; } diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 3b5db90e..ac5e9059 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -54,7 +54,10 @@ MainFrame::MainFrame , m_rectRestoredWnd(0, 0, 0, 0) , m_animationWindow() { - + m_Margins.cxLeftWidth = 0; + m_Margins.cxRightWidth = 0; + m_Margins.cyTopHeight = 0; + m_Margins.cyBottomHeight = 0; } ////////////////////////////////////////////////////////////////////////////// @@ -106,7 +109,11 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, // remove old menu SetMenu(NULL); +#ifdef _USE_AERO + HWND hWndToolBar = CreateAeroToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE); +#else HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE); +#endif TBBUTTONINFO tbi; m_toolbar.Attach(hWndToolBar); @@ -116,21 +123,34 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, tbi.cbSize = sizeof(TBBUTTONINFO); m_toolbar.GetButtonInfo(ID_FILE_NEW_TAB, &tbi); - +#ifdef _USE_AERO + // TBSTYLE_DROPDOWN : the button separator is not drawed + tbi.fsStyle |= BTNS_WHOLEDROPDOWN; +#else tbi.fsStyle |= TBSTYLE_DROPDOWN; +#endif m_toolbar.SetButtonInfo(ID_FILE_NEW_TAB, &tbi); +#ifdef _USE_AERO + CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE & ~RBS_BANDBORDERS); +#else CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE); - AddSimpleReBarBand(hWndCmdBar); +#endif + AddSimpleReBarBand(hWndCmdBar, NULL, FALSE); AddSimpleReBarBand(hWndToolBar, NULL, TRUE); +#ifdef _USE_AERO + // we remove the grippers + CReBarCtrl rebar(m_hWndToolBar); + rebar.LockBands(true); +#endif + CreateStatusBar(); // initialize tabs UpdateTabsMenu(m_CmdBar.GetMenu(), m_tabsMenu); SetReflectNotifications(true); -// SetTabStyles(CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_BOLDSELECTEDTAB); - CreateTabWindow(m_hWnd, rcDefault, CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_BOLDSELECTEDTAB); + CreateTabWindow(m_hWnd, rcDefault, CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_HOTTRACK); // create initial console window(s) if (m_startupTabs.size() == 0) @@ -1094,7 +1114,18 @@ LRESULT MainFrame::OnTabMiddleClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandl if (pTabItem == NULL) { - CreateNewConsole(0); + + // I prefer choose my console with the good environment ... + // CreateNewConsole(0); + + if (!m_tabsMenu.IsNull()) + { + // a priori y a une petite inversion X et Y ... + CPoint point(pTabItems->pt.y, pTabItems->pt.x); + CPoint screenPoint(point); + this->m_TabCtrl.ClientToScreen(&screenPoint); + m_tabsMenu.TrackPopupMenu(0, screenPoint.x, screenPoint.y, m_hWnd); + } } else { @@ -1537,82 +1568,7 @@ void MainFrame::AdjustWindowRect(CRect& rect) } rect.bottom += GetTabAreaHeight(); //+0 -// rect.right += 0; - -// TRACE(L"AdjustWindowRect: %ix%i\n", rect.Width(), rect.Height()); -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -/* -void MainFrame::AdjustAndResizeConsoleView(CRect& rectView) -{ - // adjust the active view -// if (m_activeView.get() == NULL) return; - - -// GetClientRect(&rectView); - -/ * - if (m_bToolbarVisible) - { - - CRect rectToolBar(0, 0, 0, 0 ); - CRect rectToolBarBorders(0, 0, 0, 0); - CReBarCtrl rebar(m_hWndToolBar); - int nBandIndex = rebar.IdToIndex(ATL_IDW_BAND_FIRST + 1); - - rebar.GetRect(nBandIndex, &rectToolBar); - rebar.GetBandBorders(nBandIndex, &rectToolBarBorders); - rectView.bottom -= rectToolBar.bottom - rectToolBar.top; - - rectView.bottom -= rectToolBarBorders.top + rectToolBarBorders.bottom; - } - - if (m_bStatusBarVisible) - { - CRect rectStatusBar(0, 0, 0, 0); - - ::GetWindowRect(m_hWndStatusBar, &rectStatusBar); - rectView.bottom -= rectStatusBar.bottom - rectStatusBar.top; - } - - rectView.bottom -= GetTabAreaHeight(); //+0 -* / - - // adjust the active view - if (m_activeView.get() == NULL) return; - - m_activeView->AdjustRectAndResize(rectView); - - // for other views, first set view size and then resize their Windows consoles - for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) - { - if (it->second->m_hWnd == m_activeView->m_hWnd) continue; - - it->second->SetWindowPos( - 0, - 0, - 0, - rectView.right - rectView.left, - rectView.bottom - rectView.top, - SWP_NOMOVE|SWP_NOZORDER|SWP_NOSENDCHANGING); - - it->second->AdjustRectAndResize(rectView); - } } -*/ - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// @@ -1743,26 +1699,54 @@ void MainFrame::UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu) for (it; it != tabDataVector.end(); ++it, ++dwId) { CMenuItemInfo subMenuItem; -/* - ICONINFO iconInfo; - BITMAP bmp; - - ::GetIconInfo(tabDataVector[dwId-ID_NEW_TAB_1]->tabSmallIcon, &iconInfo); - ::GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmp); -*/ subMenuItem.fMask = MIIM_STRING | MIIM_ID; -/* - subMenuItem.fMask = MIIM_BITMAP | MIIM_ID | MIIM_TYPE; - subMenuItem.fType = MFT_BITMAP; -*/ subMenuItem.wID = dwId; -// subMenuItem.hbmpItem = iconInfo.hbmColor; subMenuItem.dwTypeData = const_cast((*it)->strTitle.c_str()); subMenuItem.cch = static_cast((*it)->strTitle.length()); tabsMenu.InsertMenuItem(dwId-ID_NEW_TAB_1, TRUE, &subMenuItem); -// tabsMenu.SetMenuItemBitmaps(dwId, MF_BYCOMMAND, iconInfo.hbmColor, NULL); + + // To draw icons with good transparency + CIcon tabSmallIcon; + + // on essaye de charger l'icone + if( tabDataVector[dwId-ID_NEW_TAB_1]->strIcon.length() > 0 ) + { + tabSmallIcon.Attach( + static_cast( + ::LoadImage( + NULL, + Helpers::ExpandEnvironmentStrings(tabDataVector[dwId-ID_NEW_TAB_1]->strIcon).c_str(), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR|LR_LOADFROMFILE))); + } + else + { + tabSmallIcon.Attach( + static_cast( + ::LoadImage( + ::GetModuleHandle(NULL), + MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR))); + } + + CBitmap bmpCopy; + bmpCopy.CreateCompatibleBitmap(this->GetDC(),16,16); + CDC dc; + dc.CreateCompatibleDC(this->GetDC()); + dc.SelectBitmap(bmpCopy.m_hBitmap); + dc.FillSolidRect(0,0,16,16,::GetSysColor(COLOR_MENU)); + dc.DrawIconEx(0,0,tabSmallIcon.m_hIcon,16,16); + + tabDataVector[dwId-ID_NEW_TAB_1]->hMenuBitmap = (HBITMAP) CopyImage(bmpCopy.m_hBitmap,IMAGE_BITMAP,(int)GetSystemMetrics(SM_CXMENUCHECK),(int)GetSystemMetrics(SM_CYMENUCHECK),0); + + tabsMenu.SetMenuItemBitmaps(dwId, MF_BYCOMMAND, tabDataVector[dwId-ID_NEW_TAB_1]->hMenuBitmap, tabDataVector[dwId-ID_NEW_TAB_1]->hMenuBitmap); } // set tabs menu as popup submenu @@ -2131,7 +2115,6 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal // adjust for the toolbar height CReBarCtrl rebar(m_hWndToolBar); -// clientRect.top += rebar.GetBarHeight() - 4; clientRect.bottom -= rebar.GetBarHeight(); if (m_bStatusBarVisible) @@ -2201,87 +2184,51 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal m_dwWindowWidth = rectWindow.Width(); m_dwWindowHeight= rectWindow.Height(); -/* - CRect clientRect; - GetClientRect(&clientRect); + SetMargins(); +} - if (bMaximizing) - { - // adjust for the toolbar height - CReBarCtrl rebar(m_hWndToolBar); - clientRect.top += rebar.GetBarHeight() - 4; +////////////////////////////////////////////////////////////////////////////// - if (m_bStatusBarVisible) - { - CRect rectStatusBar(0, 0, 0, 0); - ::GetWindowRect(m_hWndStatusBar, &rectStatusBar); - clientRect.bottom -= rectStatusBar.bottom - rectStatusBar.top; - } +////////////////////////////////////////////////////////////////////////////// - clientRect.top += GetTabAreaHeight(); //+0 +void MainFrame::SetMargins(void) +{ + CReBarCtrl rebar(m_hWndToolBar); + m_Margins.cyTopHeight = rebar.GetBarHeight() + m_nTabAreaHeight; + SetTransparency(); } - if (bResizeConsole) +void MainFrame::SetTransparency() { -// AdjustAndResizeConsoleView(clientRect); - - // adjust the active view - if (m_activeView.get() == NULL) return; + // set transparency + StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; + TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; - m_activeView->AdjustRectAndResize(clientRect); + // RAZ + SetWindowLong( + GWL_EXSTYLE, + GetWindowLong(GWL_EXSTYLE) & ~WS_EX_LAYERED); - // for other views, first set view size and then resize their Windows consoles - for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) +#ifdef _USE_AERO + BOOL fEnabled = FALSE; + DwmIsCompositionEnabled(&fEnabled); + if( fEnabled ) { - if (it->second->m_hWnd == m_activeView->m_hWnd) continue; - - it->second->SetWindowPos( - 0, - 0, - 0, - clientRect.Width(), - clientRect.Height(), - SWP_NOMOVE|SWP_NOZORDER|SWP_NOSENDCHANGING); - - it->second->AdjustRectAndResize(clientRect); - } + if( stylesSettings.bCaption ) + { + ::DwmExtendFrameIntoClientArea(m_hWnd, &m_Margins); } else { - if (m_activeView.get() == NULL) return; - - m_activeView->GetRect(clientRect); + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE; + bb.fEnable = FALSE; + bb.hRgnBlur = NULL; + ::DwmEnableBlurBehindWindow(m_hWnd, &bb); } - - AdjustWindowRect(clientRect); - - SetWindowPos( - 0, - 0, - 0, - clientRect.Width(), - clientRect.Height() + 4, - SWP_NOMOVE|SWP_NOZORDER|SWP_NOSENDCHANGING); - - // update window width and height - CRect rectWindow; - - GetWindowRect(&rectWindow); - m_dwWindowWidth = rectWindow.Width(); - m_dwWindowHeight= rectWindow.Height(); -*/ } - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -void MainFrame::SetTransparency() -{ - // set transparency - TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; +#endif switch (transparencySettings.transType) { @@ -2327,14 +2274,30 @@ void MainFrame::SetTransparency() break; } - default : + case transGlass : { - SetWindowLong( - GWL_EXSTYLE, - GetWindowLong(GWL_EXSTYLE) & ~WS_EX_LAYERED); +#ifdef _USE_AERO + if( fEnabled ) + { + if( stylesSettings.bCaption ) + { + MARGINS m = {-1,-1,-1,-1}; + ::DwmExtendFrameIntoClientArea(m_hWnd, &m); } + else + { + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_TRANSITIONONMAXIMIZED; + bb.fEnable = TRUE; + bb.fTransitionOnMaximized = TRUE; + bb.hRgnBlur = NULL; + ::DwmEnableBlurBehindWindow(m_hWnd, &bb); + } + } +#endif - + break; + } } } @@ -2421,6 +2384,9 @@ void MainFrame::UnregisterGlobalHotkeys() void MainFrame::CreateStatusBar() { m_hWndStatusBar = m_statusBar.Create(*this); +#ifdef _USE_AERO + aero::Subclass(m_ASB, m_hWndStatusBar); +#endif UIAddStatusBar(m_hWndStatusBar); int arrPanes[] = { ID_DEFAULT_PANE, IDPANE_ROWS_COLUMNS }; diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 8e20263e..550f5ca2 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -33,7 +33,11 @@ class MainFrame public: DECLARE_FRAME_WND_CLASS(L"Console_2_Main", IDR_MAINFRAME) +#ifdef _USE_AERO + aero::CCommandBarCtrl m_CmdBar; +#else CCommandBarCtrl m_CmdBar; +#endif MainFrame ( @@ -210,6 +214,7 @@ class MainFrame void ResizeWindow(); void AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore = false); + void SetMargins(); void SetTransparency(); void CreateAcceleratorTable(); void RegisterGlobalHotkeys(); @@ -268,6 +273,8 @@ class MainFrame shared_ptr m_animationWindow; + MARGINS m_Margins; + }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/SelectionHandler.h b/Console/SelectionHandler.h index 5b135f0a..3c639a00 100644 --- a/Console/SelectionHandler.h +++ b/Console/SelectionHandler.h @@ -50,9 +50,9 @@ class SelectionHandler void BitBlt(CDC& offscreenDC); + void GetSelectionCoordinates(COORD& coordStart, COORD& coordEnd); private: - void GetSelectionCoordinates(COORD& coordStart, COORD& coordEnd); void GetFillRect(const COORD& coordStart, const COORD& coordEnd, CRect& fillRect); private: diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index 52fb495c..19ad86df 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -221,7 +221,8 @@ enum TransparencyType { transNone = 0, transAlpha = 1, - transColorKey = 2 + transColorKey = 2, + transGlass = 3 }; ////////////////////////////////////////////////////////////////////////////// @@ -585,9 +586,15 @@ struct TabData , backgroundImageType(bktypeNone) , crBackgroundColor(RGB(0, 0, 0)) , imageData() + , hMenuBitmap(NULL) { } + ~TabData() + { + ::DeleteObject(hMenuBitmap); + } + // custom shell settings wstring strTitle; wstring strIcon; @@ -602,6 +609,8 @@ struct TabData COLORREF crBackgroundColor; ImageData imageData; + + HBITMAP hMenuBitmap; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/res/toolbar_aero.bmp b/Console/res/toolbar_aero.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0744fca97c044176bfdd9606caf0c0af117ee0e5 GIT binary patch literal 7222 zcmds6Sx}T$8g**sX&z?sG*vT|Nu@GXQ|2L4m6@7YF`J_qvzVQzi7_q^7D0m~FvgHX zKon2}T4Yh#5oJ+aKx9Xto2ECq8=7WoXlR;lXpp5Fn#gwMeixgaf+P=_%wP3!@4uXL z?!D*#?!AAr_3h^#-@uRO*x!vTj62u~k`=$rRZ>-TSn zkMBS&3o3d2s~r&ezYEF9kFnY~{8apEyg%1<_vmAI%KK&f(Q6Yg>3pTO{M!Es{66TJ z74NO|{CckuCvmU$dGUAeW6CywiIHAR44W}I(uYZ_Rj9bWQtf!`wDzlObnZK?b5Sm>rj*B5gA*gA0%H)*VgLmA|Rp%F9C*8*7D zW=nGu&{Gc>WEiscqAqY3wjWP}?~P{o-)YBJxjOh|x57886|Gs{t_#1kEs6WL;!ePB zG~SCwTlH16vZ&9GLeAG8Abii(HQS!g=7gq_bo8}KG0>^z(c4^$hPw&K@_lVh{L=Q& z`IFu+!MXS>4itxA%a$!TP!t09(nvh<`3sBqwx>HIpfVPlllS4VvoGQgk+0%$!JBw0 z?t?|ot)#K^8es@a9K=PO#7!E1343u(K6&tmm>e5i)xSym5acI!@|+7O>Vi{@8tygK&QMI-Kuh2|8o1P_=Q{x>(BbXg#=9j_m2Fd zpgg3xl%9JcbTeMha6?d496Sq7AykxvGc~C=SDS$-X%?Qo{K*g2Bn)ARgSd#3xJiSw zNRzZh;hv}oISBEIou~=g12GFKrNJKn<0Gs3NB3l>X8jAUFksiE1~|o$hf2IBP;&p) zgQqsoapQ|^P-X|BwKNUo0yh+gJL4YnBQJO#ZlC-Vw@&VbBKsU_GL9qiljV6>9rqu5~++lrey`K%E`aW)bJD(3pNl92MUJKoisD|4(uf5H^b1e<$ z`S<4|oAH}~jd(F-FHTm)!~Jd$4(0{Gjg7NcVHmuNBXB`+1J5SAtf{fI4TK>qaS#`A z5;tj(7HN{UIMf-V114DeyJ58$VCy%+HqZlOv4HtE4E91}+N{O2NrNe)3X|P3Oz5gG zW9xz&>o@{*i}w!(3pfD?v-y z)j2$kTS<92OalWjJ$L{!i{8OO^bHO1u&^?*;yMoI1R_S0k7APwo+XiZCUQ4+2Du`U z;eX54rtKLXI3rGlZ)p^wWSJ1ivibPO*4@IUbT7_H+@wKTr0MW%C4IsWmOLab;v{a; zAT81)ZN-^`=<7FN+^EHPPxEYP(7;$i{#h}@{G*ueQDdT0iiaISjJK3x+G>V8WH&r4hRm8h9?w`nNWo{3{E218t=VXuJ^yar|La#~easv^yT?8!$0GijuP~ zC_3YULN=d@62C%yVKm|n&hKedIpG-UYCy}~m_>Mpj|=g#Yp2=!AV*QS+nk4~si|l) z7@$xpA(P13DZn(kBdIiG#R^lYAr%(jra5OW8bS z8|+=dzw?-3bL14;uS^-$m^8@ouw4jyQweP9o0u3fGXFl}{s|O)*q_ycPcxdaCq>J1 zvH3>ey71J7ih#}N7T<&_?LQD*^nx(X6T;X-80^$wlKDqIlt;R<_zdOe4?$nU-t7;c zpX-0~Z2_#t7N|46UWA{pTVbClPhKEiN1z0(@^9gq^*gEoG@3FS_i5VS^T;IPXRNHR<&b zOC+eSu7*e?LQPE#A9D%2M&nO8Nq(r9hus#-GXLlr-Fr6K72B?U$uWc_--wGiiJLS? zYpH*0=@Tb$FV&ZvBmXQIH`HUy(15WnHAeMyZ2pYK%-91=b%-$8DaJ##=8ZMvW9Fd^ z69yp$Dx*<#(VzR5qmf}KTI8RWjj520b7f^E4;pKsP`J!X^02eFcbR{5jqWY=j5vtP!AlyX zwbZ{Kt1pRgVg9jop7}>H)~SS5CqYknEPwZ>ZGD)wSun-E_a=tAF~Qb7OGzkXakKM3 zeYa<{4#E3w2Rv>u|JXcAb7>QsKWXo=8eYM4Dfb+QBEbV@Hr^UG2dYwzL7C*s#(j*3 zEXfBlmY0guW6{rG6N217ap8Z*D+c*0IS3aYC!1EIX)4@+Y;ESjoC+Ue=( z5VNswGa6^3rw6)6(QYz&i zj=ujCeF<9!>}>uV?NqV6Q^M9Eg|&tCu{sf^iddG1=Xt17y`fA#3TeU-R3*;8yX0SX z`v`oCI&ri>kHdNGJQpednsNjAK9u${@|2@cB>Nzb{VpRBxX-oS(FaAe6I$+s!z9h) z-yUlAoj~(vS9K;|7u8pep}i~(s_Un4!+YB@yhV`@JDb}FnroP5Aao^{U?1ql*nk1X z+FaCM^M|Rf7$b&8H0Q@I!r!}h4;dL5bNfNZzHqgY#=D@PV2*?8bZxcgmtH3=(scCw zr|5J4hAbHEknym#i7~7#!ywxaSlM@kjqSl@Y|U_JEiK8vTU}NhFEilP_;$P+r^B{b z9kx=$=tB~O5^svKx?PvegF z>fi6f>OzcL^cd_=p_|RA&ADOB%hPBtNkG3=44bJ1UF9jO_GMvPekpZHgezO$%@}PJ z!ltW%wYds|>H^rU1F&{f!&G?@RY}3C_W2*5C*p#n6S)Q}-bvKs?%*{1G{ZcozT zovn$jJjTpAjIr+{vp9E6eFx7krL2wefZc9q^Nf*25Brv9-|>ANEcXoPVZZT75>Bky z=l4!r;kmWR?+OZrW)RS3<3aVmeV)qieH1+Z&AgtmQO56uJYol==UzkY`T5^V)`O*I zh8pj~rY(n6Q;Gpq@tS>DFYo`_b0UE^qykS!+4mLg2c;||k#4AEd0CZu<_GnA>Hi?; O{ArK1bMEIHlm7yEMYYuc literal 0 HcmV?d00001 diff --git a/Console/resource.h b/Console/resource.h index e9491450..acf7b0e1 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -91,9 +91,9 @@ #define IDC_SPIN_BUFFER_COLUMNS2 1066 #define IDC_STATIC_INACTIVE_ALPHA 1067 #define IDC_TRANSPARENCY_TYPE 1068 -#define IDC_TRANSPARENCY_TYPE1 1069 -#define IDC_TRANSPARENCY_TYPE2 1070 -#define IDC_TRANSPARENCY_TYPE3 1071 +#define IDC_TRANSPARENCY_TYPE2 1069 +#define IDC_TRANSPARENCY_TYPE3 1070 +#define IDC_TRANSPARENCY_TYPE4 1071 #define IDC_KEY_COLOR 1072 #define IDC_STATIC_ACTIVE_WINDOW 1073 #define IDC_STATIC_INACTIVE_WINDOW 1074 @@ -213,6 +213,10 @@ #define IDC_COMBO_SMOOTHING 1169 #define IDC_CHECK_LEAVE_HIGHLIGHTED 1170 #define IDC_CHECK_START_HIDDEN 1171 +#define IDC_RADIO1 1172 +#define IDC_APPTEXT 1173 +#define IDC_APPICON 1174 +#define ID_RENAME_TAB_OK 1175 #define ID_NEW_TAB_1 2000 #define ID_SWITCH_TAB_1 2100 #define ID_NEXT_TAB 2200 @@ -236,9 +240,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 215 +#define _APS_NEXT_RESOURCE_VALUE 222 #define _APS_NEXT_COMMAND_VALUE 32794 -#define _APS_NEXT_CONTROL_VALUE 1172 +#define _APS_NEXT_CONTROL_VALUE 1176 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/Console/stdafx.h b/Console/stdafx.h index 5b1349b8..1989418e 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -6,10 +6,17 @@ #pragma once // Change these values to use different versions +#ifdef _USE_AERO +#define WINVER 0x0600 +#define _WIN32_WINNT 0x0600 +#define _WIN32_IE 0x0700 +#define _RICHEDIT_VER 0x0200 +#else #define WINVER 0x0501 #define _WIN32_WINNT 0x0501 #define _WIN32_IE 0x0400 #define _RICHEDIT_VER 0x0100 +#endif ////////////////////////////////////////////////////////////////////////////// @@ -39,18 +46,27 @@ extern CAppModule _Module; #include #pragma warning(pop) -#include "userenv.h" +#include #pragma warning(push) #pragma warning(disable: 4189 4267) -#include "atlgdix.h" +#include + +#ifdef _USE_AERO +#include +#include +#include "wtlaero.h" +#pragma comment (lib, "gdiplus.lib") +#endif #include "CustomTabCtrl.h" #include "DotNetTabCtrl.h" -//#include "SimpleTabCtrls.h" -//#include "SimpleDlgTabCtrls.h" +#ifdef _USE_AERO +#include "resource.h" +#include "AeroTabCtrl.h" +#endif #include "TabbedFrame.h" -//#include "TabbedMDI.h" + #pragma warning(pop) #include diff --git a/Console/wtlaero.h b/Console/wtlaero.h new file mode 100644 index 00000000..3fde0847 --- /dev/null +++ b/Console/wtlaero.h @@ -0,0 +1,1584 @@ +// WtlAero.h +// +// WTL::aero namespace: classes and functions supporting the Vista(r) Aero visual style +// +// Written by Alain Rist (ar@navpoch.com) +// Copyright (c) 2007 Alain Rist. +// +// AR 05.31.2007 CodeProject release +// AR 06.05.2007 CTabView: fixed unthemed environment issues, added DrawMoveMark(). +// +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. +// + +#ifndef __WTL_AERO_H__ +#define __WTL_AERO_H__ + +#pragma once + +#if !defined _WTL_VER || _WTL_VER < 0x800 + #error WtlAero.h requires the Windows Template Library 8.0 +#endif + +#if _WIN32_WINNT < 0x0600 + #error WtlAero.h requires _WIN32_WINNT >= 0x0600 +#elif !defined(NTDDI_VERSION) || (NTDDI_VERSION < NTDDI_LONGHORN) + #error WtlAero.h requires the Microsoft® Windows® Software Development Kit for Windows Vista™ +#endif + +#if !defined _UNICODE && !defined UNICODE + #error WtlAero.h requires Unicode +#endif + +#ifndef __ATLTHEME_H__ + #include "atltheme.h" +#endif + +#include + +#pragma comment (lib, "dwmapi.lib") + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// aero::CAeroBase - Base class for Aero translucency (when available) +// aero::CAeroImpl - enables Aero translucency (when available) for any window +// aero::CWindowImpl - Implements a Aero window +// aero::CDialogImpl - dialog implementation of Aero translucency (when available) +// aero::CCtrl - implementation of Aero drawing for system controls +// aero::CTabCtrl - Aero drawing Tab control +// aero::CReBarCtrl - Aero drawing ReBar control +// aero::CToolBarCtrl - Aero drawing ToolBar Control +// aero::CStatusBarCtrl - Aero drawing StatusBar Control +// aero::CStatic - Aero drawing Static control +// aero::CButton - Aero drawing Button control +// aero::CFrameWindowImpl - frame implementation of Aero translucency (when available) +// aero::CCtrlImpl - implementation of Aero drawing for user and WTL defined controls +// aero::CPrintPreviewWindow - Aero drawing WTL::CPrintPreviewWindow control +// aero::CCommandBarCtrl - Aero drawing WTL::CCommandBarCtrl control +// aero::CTabView - Aero drawing WTL::CTabView control +// aero::CPaneContainer - Aero drawing WTL::CPaneContainer control +// aero::CSplitterImpl - Aero drawing splitter implementation for any window +// aero::CSplitterWindowImpl - Implements Aero drawing splitter windows +// aero::CSplitterWindowT - Aero drawing splitter windows +// aero::CSplitterWindow - Vertical Aero drawing splitter window to be used as is +// aero::CHorSplitterWindow - Horizontal Aero drawing splitter window to be used as is +// +// namespace helper functions +// +// aero::IsSupported() +// aero::IsComposing() +// aero::IsOpaqueBlend() +// aero::Subclass() + +namespace WTL +{ +namespace aero +{ + +/////////////////////////////////////////////////////////////////////////////// +// WTL::aero helper functions + +inline bool IsSupported() +{ + return CBufferedPaintBase::IsBufferedPaintSupported(); +} + +inline bool IsComposing() +{ + BOOL bEnabled = FALSE; + return IsSupported() ? SUCCEEDED(DwmIsCompositionEnabled(&bEnabled)) && bEnabled : false; +} + +inline bool IsOpaqueBlend() +{ + BOOL bOpaqueBlend = FALSE; + DWORD dwColor; + return IsSupported() && SUCCEEDED(DwmGetColorizationColor(&dwColor, &bOpaqueBlend)) ? bOpaqueBlend == TRUE : false; +} + +template + +inline static BOOL Subclass(TCtrl& Ctrl, HWND hCtrl) +{ + ATLASSERT(::IsWindow(hCtrl)); + return IsSupported() ? Ctrl.SubclassWindow(hCtrl) : FALSE; +} + +/////////////////////////////////////////////////////////////////////////////// +// aero::CAeroBase - Base class for Aero translucency (when available) + +template +class CAeroBase : + public WTL::CThemeImpl +{ +public: + CAeroBase(LPCWSTR lpstrThemeClassList = L"globals") + { + SetThemeClassList(lpstrThemeClassList); + } + + bool IsTheming() const + { + return m_hTheme != 0; + } + + template + BOOL Subclass(TCtrl& Ctrl, INT idCtrl) + { + return aero::Subclass(Ctrl, static_cast(this)->GetDlgItem(idCtrl)); + } + + bool DrawPartText(HDC dc, int iPartID, int iStateID, LPCTSTR pStr, LPRECT prText, UINT uFormat, DTTOPTS &dto) + { + HRESULT hr = S_FALSE; + if(IsTheming()) + if (IsSupported()) + hr = DrawThemeTextEx (dc, iPartID, iStateID, pStr, -1, uFormat, prText, &dto ); + else + hr = DrawThemeText(dc, iPartID, iStateID, pStr, -1, uFormat, 0, prText); + else + hr = CDCHandle(dc).DrawText(pStr, -1, prText, uFormat) != 0 ? S_OK : S_FALSE; + + return SUCCEEDED(hr); + } + + bool DrawPartText(HDC dc, int iPartID, int iStateID, LPCTSTR pStr, LPRECT prText, UINT uFormat, + DWORD dwFlags = DTT_COMPOSITED, int iGlowSize = 0) + { + DTTOPTS dto = {sizeof(DTTOPTS)}; + dto.dwFlags = dwFlags; + dto.iGlowSize = iGlowSize; + return DrawPartText(dc, iPartID, iStateID, pStr, prText, uFormat, dto); + } + + bool DrawText(HDC dc, LPCTSTR pStr, LPRECT prText, UINT uFormat, DTTOPTS &dto) + { + return DrawPartText(dc, 1, 1, pStr, prText, uFormat, dto); + } + + bool DrawText(HDC dc, LPCTSTR pStr, LPRECT prText, UINT uFormat, DWORD dwFlags = DTT_COMPOSITED, int iGlowSize = 0) + { + return DrawPartText(dc, 1, 1, pStr, prText, uFormat, dwFlags, iGlowSize); + } + +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CAeroImpl - implementation of Aero translucency (when available) + +template +class CAeroImpl : + public WTL::CBufferedPaintImpl, + public CAeroBase + +{ +public: + CAeroImpl(LPCWSTR lpstrThemeClassList = L"globals") : CAeroBase(lpstrThemeClassList) + { + m_PaintParams.dwFlags = BPPF_ERASE; + MARGINS m = {-1}; + m_Margins = m; + } + + MARGINS m_Margins; + + bool SetMargins(MARGINS& m) + { + m_Margins = m; + T* pT = static_cast(this); + return pT->IsWindow() && IsComposing() ? SUCCEEDED(DwmExtendFrameIntoClientArea(pT->m_hWnd, &m_Margins)) : true; + } + + bool SetOpaque(bool bOpaque = true) + { + MARGINS m = {bOpaque - 1}; + return SetMargins(m); + } + + bool SetOpaque(RECT &rOpaque) + { + T* pT = static_cast(this); + RECT rClient; + pT->GetClientRect(&rClient); + MARGINS m = {rOpaque.left, rClient.right - rOpaque.right, rOpaque.top, rClient.bottom - rOpaque.bottom}; + return SetMargins(m); + } + + bool SetOpaqueUnder(ATL::CWindow wChild) + { + T* pT = static_cast(this); + ATLASSERT(wChild.IsWindow()); + ATLASSERT(pT->IsChild(wChild)); + + RECT rChild; + wChild.GetWindowRect(&rChild); + pT->ScreenToClient(&rChild); + + return SetOpaque(rChild); + } + + bool SetOpaqueUnder(UINT uID) + { + return SetOpaqueUnder(static_cast(this)->GetDlgItem(uID)); + } + +// implementation + void DoPaint(CDCHandle dc, RECT& rDest) + { + T* pT = static_cast(this); + + RECT rClient; + pT->GetClientRect(&rClient); + + RECT rView = {rClient.left + m_Margins.cxLeftWidth, rClient.top + m_Margins.cyTopHeight, + rClient.right - m_Margins.cxRightWidth, rClient.bottom - m_Margins.cyBottomHeight}; + + if (!IsComposing()) + if (IsTheming()) + pT->DrawThemeBackground(dc, WP_FRAMEBOTTOM, pT->m_hWnd == GetFocus() ? FS_ACTIVE : FS_INACTIVE, &rClient, &rDest); + else + dc.FillSolidRect(&rClient, ::GetSysColor(COLOR_MENUBAR)); + + if ((m_Margins.cxLeftWidth != -1) && !::IsRectEmpty(&rView)) + { + dc.FillSolidRect(&rView, ::GetSysColor(COLOR_WINDOW)); + if (!m_BufferedPaint.IsNull()) + m_BufferedPaint.MakeOpaque(&rView); + } + else + ::SetRectEmpty(&rView); + + pT->Paint(dc, rClient, rView, rDest); + } + + // Overrideables + void Paint(CDCHandle /*dc*/, RECT& /*rClient*/, RECT& /*rView*/, RECT& /*rDest*/) + {} + + void OnComposition() + {} + + void OnColorization() + {} + + BEGIN_MSG_MAP(CAeroImpl) + CHAIN_MSG_MAP(CThemeImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) + MESSAGE_HANDLER(WM_DWMCOMPOSITIONCHANGED, OnCompositionChanged) + MESSAGE_HANDLER(WM_DWMCOLORIZATIONCOLORCHANGED, OnColorizationChanged) + CHAIN_MSG_MAP(CBufferedPaintImpl) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if (IsThemingSupported()) + OpenThemeData(); + + if (IsComposing()) + ::DwmExtendFrameIntoClientArea(static_cast(this)->m_hWnd, &m_Margins); + return bHandled = FALSE; + } + + LRESULT OnActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if (!IsComposing() && IsTheming()) + static_cast(this)->Invalidate(FALSE); + return bHandled = FALSE; + } + + LRESULT OnCompositionChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if (IsComposing()) + SetMargins(m_Margins); + static_cast(this)->OnComposition(); + return bHandled = FALSE; + } + + LRESULT OnColorizationChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + static_cast(this)->OnColorization(); + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CWindowImpl - Implements a Aero window + +template + +class ATL_NO_VTABLE CWindowImpl : + public ATL::CWindowImpl< T, TBase, TWinTraits >, + public CAeroImpl +{ +public: + DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, -1) + + CWindowImpl(LPCWSTR lpstrThemeClassList = L"window") : CAeroImpl(lpstrThemeClassList) + {} + + typedef CAeroImpl _baseAero; + + void Paint(CDCHandle dc, RECT& rClient, RECT& rView, RECT& rDest) + {} + + BEGIN_MSG_MAP(CWindowImpl) + CHAIN_MSG_MAP(_baseAero) + END_MSG_MAP() +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CDialogImpl - dialog implementation of Aero translucency (when available) + +template +class ATL_NO_VTABLE CDialogImpl : + public ATL::CDialogImpl, + public CAeroImpl +{ +public: + CDialogImpl(LPCWSTR lpstrThemeClassList = L"dialog") : CAeroImpl(lpstrThemeClassList) + {} + + void Paint(CDCHandle dc, RECT& /*rClient*/, RECT& rView, RECT& rDest) + { + if (!::IsRectEmpty(&rView)) + { + if (IsTheming()) + DrawThemeBackground(dc, WP_DIALOG, 1, &rView, &rDest); + else + dc.FillSolidRect(&rView, GetSysColor(COLOR_BTNFACE)); + } + } + + BEGIN_MSG_MAP(CDialogImpl) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + CHAIN_MSG_MAP(CAeroImpl) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + SendMessage(WM_CREATE); + if (IsThemingSupported()) + EnableThemeDialogTexture(ETDT_ENABLE); + return bHandled = FALSE; + } + +}; + +#ifdef __ATLCTRLS_H__ + +/////////////////////////////////////////////////////////////////////////////// +// aero::CCtrl - implementation of Aero drawing for system controls +// Note: This class is intended for system themed control specializations + +template + +class CCtrl : + public WTL::CBufferedPaintWindowImpl, TBase>, + public CAeroBase > +{ +public: + typedef CAeroBase > baseAero; + typedef WTL::CBufferedPaintWindowImpl, TBase> baseWindow; + + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + + // creation and initilization + CCtrl(LPCWSTR lpstrThemeClassList = GetThemeName()) : baseAero(lpstrThemeClassList) + { + m_PaintParams.dwFlags = BPPF_ERASE; + } + + CCtrl& operator =(HWND hWnd) + { + TBase::m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + TBase baseCtrl; + if (baseCtrl.Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam) != NULL) + SubclassWindow(baseCtrl.m_hWnd); + return m_hWnd; + } + + BOOL SubclassWindow(HWND hWnd) + { + ATLASSERT(IsSupported()); + if(baseWindow::SubclassWindow(hWnd)) + OpenThemeData(); + return m_hWnd != NULL; + } + + // specializables + static LPCWSTR GetThemeName() + { + return TBase::GetWndClassName(); + } + + void CtrlPaint(HDC hdc, RECT& /*rCtrl*/, RECT& rPaint) + { + DefCtrlPaint(hdc, rPaint); + } + + // operations + void DefCtrlPaint(HDC hdc, RECT& rPaint, bool bEraseBkGnd = false) + { + if (bEraseBkGnd) + DefWindowProc(WM_ERASEBKGND, (WPARAM)hdc, NULL); + DefWindowProc(WM_PAINT, (WPARAM)hdc, 0); + m_BufferedPaint.MakeOpaque(&rPaint); + } + + BOOL DrawCtrlBackground(HDC hdc, int nPartID, int nStateID, RECT &rCtrl, RECT &rPaint) + { + return SUCCEEDED(DrawThemeBackground(hdc, nPartID, nStateID, &rCtrl, &rPaint)); + } + + BOOL DrawCtrlEdge(HDC hdc, int nPartID, int nStateID, RECT &rCtrl, UINT uEdge = EDGE_ETCHED, UINT uFlags = BF_RECT, LPRECT pContentRect = NULL) + { + return SUCCEEDED(DrawThemeEdge(hdc, nPartID, nStateID, &rCtrl, uEdge, uFlags, pContentRect)); + } + + BOOL DrawCtrlText(CDCHandle dc, int nPartID, int nStateID, UINT uFormat, RECT &rCtrl, HFONT hFont = 0, + DWORD dwFlags = DTT_COMPOSITED, int iGlowSize = 0) + { + HRESULT hr; + RECT rText; + hr = GetThemeBackgroundContentRect(dc, nPartID, nStateID, &rCtrl, &rText); + MARGINS m = {0}; + hr = GetThemeMargins(dc, nPartID, nStateID, TMT_CONTENTMARGINS, &rText, &m); + rText.left += m.cxLeftWidth; + rText.right -= m.cxRightWidth; + int iLength = GetWindowTextLength(); + if (iLength > 0) + { + CTempBuffer sText(++iLength); + GetWindowText(sText, iLength); + + HFONT hf = dc.SelectFont(hFont == 0 ? GetFont() : hFont); + hr = DrawPartText(dc, nPartID, nStateID, sText, &rText , uFormat, dwFlags, iGlowSize); + dc.SelectFont(hf); + } + return SUCCEEDED(hr) && iLength > 0; + } + + // implementation + void DoBufferedPaint(HDC hdc, RECT& rPaint) + { + HDC hDCPaint = NULL; + RECT rCtrl; + GetClientRect(&rCtrl); + m_BufferedPaint.Begin(hdc, &rCtrl, m_dwFormat, &m_PaintParams, &hDCPaint); + ATLASSERT(hDCPaint != NULL); + CtrlPaint(hDCPaint, rCtrl, rPaint); + m_BufferedPaint.End(); + } + + void DoPaint(HDC /*hdc*/, RECT& /*rCtrl*/) + { + DefWindowProc(); + } + + BEGIN_MSG_MAP(CCtrl) + MESSAGE_HANDLER(WM_PAINT, OnPaintMsg) + MESSAGE_HANDLER(WM_ERASEBKGND, OnPaintMsg) + CHAIN_MSG_MAP(baseAero) + CHAIN_MSG_MAP(baseWindow) + END_MSG_MAP() + + LRESULT OnPaintMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(!IsComposing()) + return DefWindowProc(); + else + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Macro declaring and subclassing a control (static declaration to use in OnCreate or OnInitDialog members) + +#define AERO_CONTROL(type, name, id)\ + static aero::type name;\ + Subclass(name, id); + +/////////////////////////////////////////////////////////////////////////////// +// aero::CEdit - Aero drawing Edit control + +class CEdit : public CCtrl + +{ +public: + BEGIN_MSG_MAP(CEdit) + MESSAGE_HANDLER(EM_SETSEL, OnRedraw) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnRedraw) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnRedraw) + MESSAGE_HANDLER(WM_KEYDOWN, OnRedraw) + MESSAGE_HANDLER(WM_PASTE, OnRedraw) + CHAIN_MSG_MAP(CCtrl) + END_MSG_MAP() + + LRESULT OnRedraw(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + DefWindowProc(); + Invalidate(FALSE); + return 0; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CTabCtrl - Aero drawing Tab control + +typedef CCtrl CTabCtrl; + +inline LPCWSTR CTabCtrl::GetThemeName() +{ + return L"TAB"; +}; + +inline void CTabCtrl::CtrlPaint(HDC hdc, RECT& /*rCtrl*/, RECT& /*rPaint*/) +{ + DefWindowProc(WM_PAINT, (WPARAM)hdc, NULL); + RECT rTab; + for (int nTab = 0; GetItemRect(nTab, &rTab); nTab++) + { + rTab.right -= 3; + rTab.bottom -= 3; + m_BufferedPaint.MakeOpaque(&rTab); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CToolBarCtrl - Aero translucent ToolBar Control + +typedef CCtrl CToolBarCtrl; + +inline LPCWSTR CToolBarCtrl::GetThemeName() +{ + return L"TOOLBAR"; +}; + +inline void CToolBarCtrl::CtrlPaint(HDC hdc, RECT& /*rCtrl*/, RECT& rPaint) +{ + int nBtn = GetButtonCount(), + iHot = GetHotItem(); + + CImageList img = GetImageList(); + + int cx, cy; + img.GetIconSize(cx, cy); + + RECT rBtn; + TOOLBARPARTS part; + TOOLBARSTYLESTATES state; + + for (int i = 0; i < nBtn; i++) + { + TBBUTTONINFO tbbi = {sizeof(TBBUTTONINFO), TBIF_BYINDEX | TBIF_STATE | TBIF_STYLE | TBIF_IMAGE}; + GetButtonInfo(i, &tbbi); + + part = tbbi.fsStyle & BTNS_SEP ? TP_SEPARATOR : TP_BUTTON; + state = tbbi.fsState & TBSTATE_ENABLED ? tbbi.fsState & TBSTATE_CHECKED ? TS_CHECKED : TS_NORMAL : TS_DISABLED; + if (i == iHot) + state = tbbi.fsState & TBSTATE_PRESSED ? TS_PRESSED : TS_HOT; + + + GetItemRect(i, &rBtn); + DrawThemeBackground(hdc, part, state, &rBtn, &rPaint); + + if (part != TP_SEPARATOR) + { + RECT rbmp; + GetThemeBackgroundContentRect(hdc, part, state, &rBtn, &rbmp); + int x = rbmp.left + (rbmp.right - rbmp.left - cx) / 2; + int y = rbmp.top + (rbmp.bottom - rbmp.top - cy) / 2; + IMAGELISTDRAWPARAMS ildp = {sizeof(IMAGELISTDRAWPARAMS), img, tbbi.iImage, hdc, x, y, 0, 0, 0, 0, + CLR_NONE, CLR_NONE, ILD_PRESERVEALPHA, SRCCOPY, (state & TS_DISABLED)? ILS_SATURATE : ILS_NORMAL}; + img.DrawIndirect(&ildp); + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CStatusBarCtrl - Aero drawing StatusBar Control + +typedef CCtrl CStatusBarCtrl; + +inline LPCWSTR CStatusBarCtrl::GetThemeName() +{ + return L"STATUS"; +}; + +inline void CStatusBarCtrl::CtrlPaint(HDC hdc, RECT& /*rCtrl*/, RECT& rPaint) +{ + DefCtrlPaint(hdc, rPaint, true); +} + +/////////////////////////////////////////////////////////////////////////////// +// aero::CListBox - Aero drawing ListBox control + +typedef CCtrl CListBox; + +inline void CListBox::CtrlPaint(HDC hdc, RECT& /*rCtrl*/, RECT& rPaint) +{ + DefCtrlPaint(hdc, rPaint, true); +} + +/////////////////////////////////////////////////////////////////////////////// +// aero::CComboBox - Aero drawing ComboBox control + +inline void CCtrl::CtrlPaint(HDC hdc, RECT& /*rCtrl*/, RECT& rPaint) +{ + DefCtrlPaint(hdc, rPaint, true); +} + +class CComboBox : public CCtrl + +{ +public: + aero::CEdit m_AE; + + BOOL SubclassWindow(HWND hWnd) + { + ATLASSERT(IsSupported()); + if(baseWindow::SubclassWindow(hWnd)) + { + OpenThemeData(); + COMBOBOXINFO cbi = {sizeof(COMBOBOXINFO)}; + GetComboBoxInfo(&cbi); + if (cbi.hwndItem != NULL) + ATLVERIFY(aero::Subclass(m_AE, cbi.hwndItem)); + } + return m_hWnd != NULL; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CStatic - Aero drawing Static control + +typedef CCtrl CStatic; + +inline LPCWSTR CStatic::GetThemeName() +{ + return L"static::globals"; +}; + +inline void CStatic::CtrlPaint(HDC hdc, RECT& rCtrl, RECT& rPaint) +{ + DWORD dwStyle = GetStyle(); + + UINT uFormat = dwStyle & 0x3L; + if ((dwStyle | SS_SIMPLE) == SS_SIMPLE) + uFormat |= DT_SINGLELINE; + else + uFormat |= DT_WORDBREAK; + + + switch (dwStyle & 0xfL) + { + case SS_ICON: + case SS_BITMAP: + case SS_ENHMETAFILE: + case SS_BLACKRECT: + case SS_GRAYRECT: + case SS_WHITERECT: + case SS_BLACKFRAME: + case SS_GRAYFRAME: + case SS_WHITEFRAME: + case SS_OWNERDRAW: + DefCtrlPaint(hdc, rPaint); + break; + default: + DrawCtrlText(hdc, 1, 1, uFormat, rCtrl, 0, DTT_COMPOSITED | DTT_GLOWSIZE, 10); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// aero::CButton - Aero drawing Button control + +class CButtonThemeHelper +{ +public: + CButtonThemeHelper(DWORD dwStyle, DWORD dwState, BOOL bEnabled) + { + m_bp = _GetPart(dwStyle); + m_bs = _GetState(m_bp, dwState, bEnabled); + m_fmt = _GetFormat(m_bp, dwStyle); + } + + enum BUTTONPARTS m_bp; + int m_bs; + UINT m_fmt; + + static int _GetFormat(enum BUTTONPARTS bp, DWORD dwStyle) + { + int fmt = dwStyle & BS_MULTILINE ? DT_WORDBREAK : DT_SINGLELINE; + switch (dwStyle & BS_CENTER) + { + case BS_LEFT: + fmt |= DT_LEFT; + break; + case BS_RIGHT: + fmt |= DT_RIGHT; + break; + case BS_CENTER: + fmt |= DT_CENTER; + break; + default: + fmt |= bp == BP_PUSHBUTTON ? DT_CENTER : DT_LEFT; + } + + switch (dwStyle & BS_VCENTER) + { + case BS_TOP: + fmt |= DT_TOP; + break; + case BS_BOTTOM: + fmt |= DT_BOTTOM; + break; + case BS_VCENTER: + fmt |= DT_VCENTER; + break; + default: + if (fmt ^ BS_MULTILINE) + fmt |= bp == BP_GROUPBOX ? DT_TOP : DT_VCENTER; + } + + return fmt; + } + + static int _GetBaseButtonState(DWORD dwState, BOOL bEnabled) + { + if (!bEnabled) + return PBS_DISABLED; + if (dwState & BST_PUSHED) + return PBS_PRESSED; + if (dwState & BST_HOT) + return PBS_HOT; + return PBS_NORMAL; + } + + static int _GetState(enum BUTTONPARTS bp, DWORD dwState, BOOL bEnabled) + { + int bs = _GetBaseButtonState(dwState, bEnabled); + switch (bp) + { + case BP_PUSHBUTTON: + case BP_COMMANDLINK: + if ((bs == PBS_NORMAL) && (dwState & BST_FOCUS)) + bs = PBS_DEFAULTED_ANIMATING; + break; + case BP_CHECKBOX: + if (dwState & BST_INDETERMINATE) + { + bs += 8; + break; + } + case BP_RADIOBUTTON: + if (dwState & BST_CHECKED) + bs += 4; + } + return bs; + } + + static enum BUTTONPARTS _GetPart(DWORD dwStyle) + { + switch(dwStyle & 0xf) + { + case BS_CHECKBOX: + case BS_AUTOCHECKBOX: + case BS_3STATE: + case BS_AUTO3STATE: + return BP_CHECKBOX; + case BS_RADIOBUTTON: + case BS_AUTORADIOBUTTON: + return BP_RADIOBUTTON; + case BS_GROUPBOX: + return BP_GROUPBOX; + case BS_USERBUTTON: + case BS_OWNERDRAW: + return BP_USERBUTTON; + case BS_COMMANDLINK: + case BS_DEFCOMMANDLINK: + return BP_COMMANDLINK; + default: + return BP_PUSHBUTTON; + } + } +}; + +typedef CCtrl CButton; + +inline void CButton::CtrlPaint(HDC hdc, RECT& rCtrl, RECT& rPaint) +{ + HRESULT hr; + CButtonThemeHelper helper(GetButtonStyle(), GetState(), IsWindowEnabled()); + switch (helper.m_bp) + { + case BP_USERBUTTON: + DefCtrlPaint(hdc, rPaint); + return; + + case BP_GROUPBOX: + DefWindowProc(WM_PAINT, (WPARAM)hdc, 0); + { + int iLength = GetWindowTextLength(); + if (iLength > 0) + { + RECT rText; + CDCHandle dc(hdc); + CTempBuffer sText(++iLength); + GetWindowText(sText, iLength); + HFONT hf = dc.SelectFont(GetFont()); + hr = GetThemeTextExtent(dc, helper.m_bp, helper.m_bs, sText, -1, helper.m_fmt, &rCtrl, &rText); + ATLASSERT(SUCCEEDED(hr)); + OffsetRect(&rText, 10, 0); + m_BufferedPaint.Clear(&rText); + hr = DrawPartText(dc, helper.m_bp, helper.m_bs, (LPCWSTR)sText, &rText , helper.m_fmt, DTT_COMPOSITED | DTT_GLOWSIZE, 10); + ATLASSERT(SUCCEEDED(hr)); + dc.SelectFont(hf); + } + } + return; + + case BP_RADIOBUTTON: + case BP_CHECKBOX: + { + CBitmapHandle bm; + SIZE s; + RECT rBitmap = rCtrl; + hr = GetThemeBitmap(helper.m_bp, helper.m_bs, 0, GBF_DIRECT, bm.m_hBitmap); + ATLASSERT(SUCCEEDED(hr)); + bm.GetSize(s); + if (GetButtonStyle() & BS_RIGHTBUTTON) + rCtrl.right = rBitmap.left = rBitmap.right - s.cx - s.cx / 2; + else + rCtrl.left = rBitmap.right = rBitmap.left + s.cx + s.cx / 2; + hr = DrawThemeBackground(hdc, helper.m_bp, helper.m_bs, &rBitmap, NULL); + ATLASSERT(SUCCEEDED(hr)); + } + break; + + default: + hr = DrawCtrlBackground(hdc, helper.m_bp, helper.m_bs, rCtrl, rPaint); + ATLASSERT(SUCCEEDED(hr)); + } + hr = DrawCtrlText(hdc, helper.m_bp, helper.m_bs, helper.m_fmt, rCtrl, 0); + ATLASSERT(SUCCEEDED(hr)); +} + +#ifdef __ATLDLGS_H__ + +/////////////////////////////////////////////////////////////////////////////// +// aero::CPropertySheetImpl - Property Sheet implementation of Aero translucency (when available) + +template + +class ATL_NO_VTABLE CPropertySheetImpl : + public WTL::CPropertySheetImpl, + public CAeroImpl +{ + typedef WTL::CPropertySheetImpl basePS; +public: + + CPropertySheetImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL): + basePS(title, uStartPage, hWndParent) , CAeroImpl(L"window") + {} + + aero::CTabCtrl m_Atab; + aero::CButton m_btns[PSBTN_MAX]; + + void Paint(CDCHandle dc, RECT& /*rClient*/, RECT& rView, RECT& rDest) + { + if (!::IsRectEmpty(&rView)) + { + if (IsTheming()) + DrawThemeBackground(dc, WP_DIALOG, 1, &rView, &rDest); + else + dc.FillSolidRect(&rView, GetSysColor(COLOR_WINDOW)); + } + } + + void InitPS() + { + aero::Subclass(m_Atab, GetTabControl()); + for (int idBtn = 0 ; idBtn < PSBTN_MAX; idBtn++) + if (HWND hBtn = GetDlgItem(idBtn)) + aero::Subclass(m_btns[idBtn], hBtn); + SendMessage(WM_CREATE); + if (IsThemingSupported()) + EnableThemeDialogTexture(ETDT_ENABLE); + } + +// Callback function + static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam) + { + lParam; // avoid level 4 warning + int nRet = 0; + + if(uMsg == PSCB_INITIALIZED) + { + ATLASSERT(hWnd != NULL); + T* pT = (T*)ModuleHelper::ExtractCreateWndData(); + // subclass the sheet window + pT->SubclassWindow(hWnd); + // remove page handles array + pT->_CleanUpPages(); + + pT->InitPS(); + pT->OnSheetInitialized(); + } + + return nRet; + } + + BEGIN_MSG_MAP(CPropertySheetImpl) + CHAIN_MSG_MAP(CAeroImpl) + CHAIN_MSG_MAP(basePS) + END_MSG_MAP() +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CPropertyPageImpl - Property page implementation of Aero translucency (when available) + +template +class ATL_NO_VTABLE CPropertyPageImpl : + public WTL::CPropertyPageImpl, + public CAeroImpl + +{ +public: + typedef WTL::CPropertyPageImpl basePP; + + CPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : + basePP(title), + CAeroImpl(L"dialog") + {} + + void Paint(CDCHandle dc, RECT& /*rClient*/, RECT& rView, RECT& rDest) + { + if (!::IsRectEmpty(&rView)) + { + if (IsTheming()) + DrawThemeBackground(dc, WP_DIALOG, 1, &rView, &rDest); + else + dc.FillSolidRect(&rView, GetSysColor(COLOR_WINDOW)); + } + } + + BEGIN_MSG_MAP(CPropertyPageImpl) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + CHAIN_MSG_MAP(CAeroImpl) + CHAIN_MSG_MAP(basePP) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + SendMessage(WM_CREATE); + if (IsThemingSupported()) + EnableThemeDialogTexture(ETDT_ENABLE); + return bHandled = FALSE; + } +}; +#endif // __ATLDLGS_H__ + + +#ifdef __ATLFRAME_H__ + +/////////////////////////////////////////////////////////////////////////////// +// aero::CFrameWindowImpl - Aero frame implementation + +template +class ATL_NO_VTABLE CFrameWindowImpl : + public WTL::CFrameWindowImpl, + public CAeroImpl + +{ + typedef WTL::CFrameWindowImpl _baseClass; + +public: + CFrameWindowImpl(LPCWSTR lpstrThemeClassList = L"window") : CAeroImpl(lpstrThemeClassList) + {} + + void UpdateLayout(BOOL bResizeBars = TRUE) + { + RECT rect = { 0 }; + GetClientRect(&rect); + + // position margins + if (m_Margins.cxLeftWidth != -1) + { + rect.left += m_Margins.cxLeftWidth; + rect.top += m_Margins.cyTopHeight; + rect.right -= m_Margins.cxRightWidth; + rect.bottom -= m_Margins.cyBottomHeight; + } + + // position bars and offset their dimensions + UpdateBarsPosition(rect, bResizeBars); + + // resize client window + if(m_hWndClient != NULL) + ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOACTIVATE); + + Invalidate(FALSE); + } + + void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE) + { + // resize toolbar + if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE)) + { + RECT rectTB = { 0 }; + ::GetWindowRect(m_hWndToolBar, &rectTB); + if(bResizeBars) + { + // we move bars 2 pixels left to remove a stupid border drawed by the rebar + ::SetWindowPos(m_hWndToolBar, NULL, rect.left - 2, rect.top, + rect.right - rect.left + 2, rectTB.bottom - rectTB.top, + SWP_NOZORDER | SWP_NOACTIVATE); + ::InvalidateRect(m_hWndToolBar, NULL, FALSE); + } + rect.top += rectTB.bottom - rectTB.top; + } + + // resize status bar + if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE)) + { + RECT rectSB = { 0 }; + ::GetWindowRect(m_hWndStatusBar, &rectSB); + rect.bottom -= rectSB.bottom - rectSB.top; + if(bResizeBars) + ::SetWindowPos(m_hWndStatusBar, NULL, rect.left, rect.bottom, + rect.right - rect.left, rectSB.bottom - rectSB.top, + SWP_NOZORDER | SWP_NOACTIVATE); + } + } + + aero::CStatusBarCtrl m_ASB; + aero::CToolBarCtrl m_ATB; + + BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) + { + ATLASSERT(!::IsWindow(m_hWndStatusBar)); + m_hWndStatusBar = ::CreateStatusWindow(dwStyle | CCS_NOPARENTALIGN , lpstrText, m_hWnd, nID); + aero::Subclass(m_ASB, m_hWndStatusBar); + return (m_hWndStatusBar != NULL); + } + + BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) + { + const int cchMax = 128; // max text length is 127 for status bars (+1 for null) + TCHAR szText[cchMax]; + szText[0] = 0; + ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); + return CreateSimpleStatusBar(szText, dwStyle, nID); + } + + HWND CreateAeroToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, + DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + HWND hWndToolBar = _baseClass::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID); + if (hWndToolBar != NULL) + aero::Subclass(m_ATB, hWndToolBar); + return hWndToolBar; + } + + HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + HWND hRB = _baseClass::CreateSimpleReBarCtrl(hWndParent, dwStyle | CCS_NOPARENTALIGN, nID); + return hRB; + } + + BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + m_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle | CCS_NOPARENTALIGN, nID); + return (m_hWndToolBar != NULL); + } + + BEGIN_MSG_MAP(CFrameWindowImpl) + CHAIN_MSG_MAP(CAeroImpl) + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() +}; +#endif // __ATLFRAME_H__ +#endif // __ATLCTRLS_H__ + +/////////////////////////////////////////////////////////////////////////////// +// aero::CCtrlImpl - implementation of Aero drawing for user and WTL defined controls +// Note: This class is intended for derivation + +template +class ATL_NO_VTABLE CCtrlImpl : + public TCtrlImpl, + public CAeroImpl + +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TCtrlImpl::GetWndClassName()) + + CCtrlImpl(LPCWSTR lpstrThemeClassList = L"window") : CAeroImpl(lpstrThemeClassList) + { + m_PaintParams.dwFlags = BPPF_ERASE; + } + + void DoPaint(HDC hdc, RECT& rect) + { + BOOL bHandled = TRUE; + TCtrlImpl::OnPaint(WM_PAINT, (WPARAM) hdc, NULL, bHandled); + if (t_bOpaque) + m_BufferedPaint.MakeOpaque(&rect); + } + + BEGIN_MSG_MAP(CCtrlImpl) + CHAIN_MSG_MAP(CAeroImpl) + CHAIN_MSG_MAP(TCtrlImpl) + END_MSG_MAP() + +}; + +#ifdef __ATLCTRLW_H__ + +/////////////////////////////////////////////////////////////////////////////// +// aero::CCommandBarCtrl - Aero drawing WTL::CCommandBarCtrl control + +class CCommandBarCtrl : + public CCtrlImpl > +{ +public: + + DECLARE_WND_SUPERCLASS(_T("WTL_AeroCommandBar"), GetWndClassName()) + + CCommandBarCtrl() : CCtrlImpl(L"MENU") + {} + + void DoPaint(HDC hdc, RECT&) + { + DefWindowProc(WM_PAINT, (WPARAM) hdc, NULL); + } + + BEGIN_MSG_MAP(CCommandBarCtrl) + CHAIN_MSG_MAP(CThemeImpl) + CHAIN_MSG_MAP(CBufferedPaintImpl) + CHAIN_MSG_MAP(WTL::CCommandBarCtrlImpl) + ALT_MSG_MAP(1) // Parent window messages + NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnParentCustomDraw) + CHAIN_MSG_MAP_ALT(WTL::CCommandBarCtrlImpl, 1) + ALT_MSG_MAP(3) // Message hook messages + CHAIN_MSG_MAP_ALT(WTL::CCommandBarCtrlImpl, 3) + END_MSG_MAP() + + LRESULT OnParentCustomDraw(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) + { + if (!IsTheming()) + return WTL::CCommandBarCtrlImpl::OnParentCustomDraw(idCtrl, pnmh, bHandled); + + LRESULT lRet = CDRF_DODEFAULT; + bHandled = FALSE; + if(pnmh->hwndFrom == m_hWnd) + { + LPNMTBCUSTOMDRAW lpTBCustomDraw = (LPNMTBCUSTOMDRAW)pnmh; + CDCHandle dc = lpTBCustomDraw->nmcd.hdc; + RECT& rc = lpTBCustomDraw->nmcd.rc; + + if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT) + { + DrawThemeBackground(dc, MENU_BARBACKGROUND, m_bParentActive ? MB_ACTIVE : MB_INACTIVE, &rc); + lRet = CDRF_NOTIFYITEMDRAW; + bHandled = TRUE; + } + else if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) + { + bool bHot = ((lpTBCustomDraw->nmcd.uItemState & CDIS_HOT) == CDIS_HOT); + bool bPushed = ((lpTBCustomDraw->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED); + bool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED); + + int bis = bPushed ? MBI_PUSHED : bHot ? MBI_HOT : MBI_NORMAL; + + if(m_bFlatMenus) + { + if (bDisabled || (!m_bParentActive && !bPushed && !bHot)) + bis += 3; + if ((bHot || bPushed) && !bDisabled) + DrawThemeBackground(dc, MENU_POPUPITEM, MBI_HOT, &rc); + } + else + { + if (!m_bParentActive || bDisabled) + bis += 3; + DrawThemeBackground(dc, MENU_BARITEM, bis, &rc); + } + + CLogFont lf; + HRESULT hr = GetThemeSysFont(TMT_MENUFONT, &lf); + CFont hFont = (hr == S_OK) ? lf.CreateFontIndirect() : GetFont(); + HFONT hFontOld = NULL; + if(hFont != NULL) + hFontOld = dc.SelectFont(hFont); + + CTempBuffer szText(200); + TBBUTTONINFO tbbi = {sizeof(TBBUTTONINFO), TBIF_TEXT}; + tbbi.pszText = szText; + tbbi.cchText = 200; + GetButtonInfo((int)lpTBCustomDraw->nmcd.dwItemSpec, &tbbi); + + hr = DrawPartText(dc, MENU_BARITEM, bis, szText, &rc, + DT_SINGLELINE | DT_CENTER | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); + + if(hFont != NULL) + dc.SelectFont(hFontOld); + lRet = CDRF_SKIPDEFAULT; + bHandled = TRUE; + } + } + return lRet; + } + +}; +#endif // __ATLCTRLW_H__ + +#ifdef __ATLPRINT_H__ + +/////////////////////////////////////////////////////////////////////////////// +// aero::CPrintPreviewWindow - Aero drawing WTL::CPrintPreviewWindow control + +class CPrintPreviewWindow : public aero::CCtrlImpl + +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_AeroPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) + + void DoPaint(CDCHandle dc, RECT& rc) + { + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcArea = rcClient; + ::InflateRect(&rcArea, -m_cxOffset, -m_cyOffset); + if (rcArea.left > rcArea.right) + rcArea.right = rcArea.left; + if (rcArea.top > rcArea.bottom) + rcArea.bottom = rcArea.top; + GetPageRect(rcArea, &rc); + if (!aero::IsComposing()) + { + CRgn rgn1, rgn2; + rgn1.CreateRectRgnIndirect(&rc); + rgn2.CreateRectRgnIndirect(&rcClient); + rgn2.CombineRgn(rgn1, RGN_DIFF); + dc.SelectClipRgn(rgn2); + if (IsTheming()) + DrawThemeBackground(dc, WP_FRAMEBOTTOM, m_hWnd == GetFocus() ? FS_ACTIVE : FS_INACTIVE, + &rcClient); + else + dc.FillRect(&rcClient, ::GetSysColor(COLOR_BTNSHADOW)); + dc.SelectClipRgn(NULL); + } + dc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH)); + + WTL::CPrintPreviewWindow::DoPaint(dc, rc); + m_BufferedPaint.MakeOpaque(&rc); + } + +}; + +#endif // __ATLPRINT_H__ + +//#ifdef __ATLCTRLX_H__ + +/////////////////////////////////////////////////////////////////////////////// +// aero::CTabView - Aero drawing WTL::CTabView control + +class CTabView : + public CCtrlImpl > +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_AeroTabView"), 0, COLOR_APPWORKSPACE) + + aero::CTabCtrl m_Atab; + + bool CreateTabControl() + { + if (aero::IsSupported()) + { + m_Atab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID); + m_tab.SubclassWindow(m_Atab); + } + else + m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID); + + ATLASSERT(m_tab.m_hWnd != NULL); + if(m_tab.m_hWnd == NULL) + return false; + + m_tab.SetFont(AtlGetDefaultGuiFont()); + m_tab.SetItemExtra(sizeof(TABVIEWPAGE)); + m_cyTabHeight = CalcTabHeight(); + + return true; + } + + void GetMoveMarkRect(RECT& rect) const + { + m_tab.GetClientRect(&rect); + + RECT rcItem = { 0 }; + m_tab.GetItemRect(m_nInsertItem, &rcItem); + + int cxMoveMark = IsComposing() ? 0 : m_cxMoveMark / 2; + + if(m_nInsertItem <= m_nActivePage) + { + rect.left = rcItem.left - cxMoveMark - 1; + rect.right = rcItem.left + cxMoveMark + 1; + } + else + { + rect.left = rcItem.right - cxMoveMark - 1; + rect.right = rcItem.right + cxMoveMark + 1; + } + } + + void DrawMoveMark(int nItem) + { + if (!IsComposing()) + return WTL::CTabViewImpl::DrawMoveMark(nItem); + + RECT rect = { 0 }; + if(m_nInsertItem != -1) + { + GetMoveMarkRect(rect); + m_tab.InvalidateRect(&rect); + } + + m_nInsertItem = nItem; + + if(m_nInsertItem != -1) + { + GetMoveMarkRect(rect); + + CClientDC dcTab(m_tab.m_hWnd); + HDC hDCPaint = NULL; + m_BufferedPaint.Begin(dcTab, &rect, m_dwFormat, &m_PaintParams, &hDCPaint); + ATLASSERT(hDCPaint != NULL); + CDC dc(hDCPaint); + + CPen pen; + pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_HOTLIGHT)); + CBrush brush; + brush.CreateSolidBrush(::GetSysColor(COLOR_HOTLIGHT)); + + HPEN hPenOld = dc.SelectPen(pen); + HBRUSH hBrushOld = dc.SelectBrush(brush); + + dc.Rectangle(&rect); + + dc.SelectPen(hPenOld); + dc.SelectBrush(hBrushOld); + + m_BufferedPaint.MakeOpaque(&rect); + m_BufferedPaint.End(); + } + } + + void DoPaint(HDC hdc, RECT& rDest) + { + if (!IsComposing()) + { + RECT rClient; + GetClientRect(&rClient); + if (IsTheming()) + DrawThemeBackground(hdc, WP_FRAMEBOTTOM, FS_INACTIVE, &rClient, &rDest); + else + { + DefWindowProc(WM_ERASEBKGND, (WPARAM)hdc, NULL); + if (!m_BufferedPaint.IsNull()) + m_BufferedPaint.MakeOpaque(&rDest); + } + } + + DefWindowProc(WM_PAINT, (WPARAM)hdc, NULL); + } + +// Message map and handlers + BEGIN_MSG_MAP(CTabView) + CHAIN_MSG_MAP(CAeroImpl) + CHAIN_MSG_MAP(WTL::CTabViewImpl) + ALT_MSG_MAP(1) // tab control + CHAIN_MSG_MAP_ALT(WTL::CTabViewImpl, 1) + END_MSG_MAP() + +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CPaneContainer - Aero drawing WTL::CPaneContainer control + +class CPaneContainer : + public CCtrlImpl > +{ + // not using aero::CToolBarCtrl + class CPaneToolBar : public WTL::CToolBarCtrl + {}; + CCtrl m_Atb; + +public: + void CreateCloseButton() + { + WTL::CPaneContainerImpl::CreateCloseButton(); + aero::Subclass(m_Atb, m_tb.m_hWnd); + } + + void DrawPaneTitle(CDCHandle dc) + { + WTL::CPaneContainerImpl::DrawPaneTitle(dc); + + if (IsComposing() && !m_BufferedPaint.IsNull()) + { + RECT rect = { 0 }; + GetClientRect(&rect); + if(IsVertical()) + rect.right = rect.left + m_cxyHeader; + else + rect.bottom = rect.top + m_cxyHeader; + + m_BufferedPaint.MakeOpaque(&rect); + } + } + + // called only if pane is empty + void DrawPane(CDCHandle dc) + { + RECT rect = { 0 }; + GetClientRect(&rect); + if(IsVertical()) + rect.left += m_cxyHeader; + else + rect.top += m_cxyHeader; + + if((GetExStyle() & WS_EX_CLIENTEDGE) == 0) + dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + if (!IsComposing()) + dc.FillRect(&rect, COLOR_APPWORKSPACE); + } + +}; + +//#endif // __ATLCTRLX_H__ + +#ifdef __ATLSPLIT_H__ + +/////////////////////////////////////////////////////////////////////////////// +// aero::CSplitterImpl - Provides Aero drawing splitter support to any window + +// Aero splitter extended style +#define SPLIT_NONTRANSPARENT 0x00000008 + +template + +class CSplitterImpl : + public WTL::CSplitterImpl +{ +public: + typedef WTL::CSplitterImpl baseSplit; + + // called only if pane is empty + void DrawSplitterPane(CDCHandle dc, int nPane) + { + T* pT = static_cast(this); + RECT rect; + if(GetSplitterPaneRect(nPane, &rect)) + { + if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0) + dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + + if (!aero::IsComposing()) + dc.FillRect(&rect, COLOR_APPWORKSPACE); + } + } + + void DrawSplitterBar(CDCHandle dc) + { + T* pT = static_cast(this); + if (aero::IsComposing()) + { + if (GetSplitterExtendedStyle() & SPLIT_NONTRANSPARENT) + { + RECT rect; + GetSplitterBarRect(&rect); + pT->DrawThemeBackground(dc, WP_FRAMEBOTTOM, pT->m_hWnd == GetFocus() ? FS_ACTIVE : FS_INACTIVE, &rect) ; + } + } + else + baseSplit::DrawSplitterBar(dc); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CSplitterWindowImpl - Implements an Aero drawing splitter window + +template +class ATL_NO_VTABLE CSplitterWindowImpl : + public aero::CWindowImpl, + public aero::CSplitterImpl + +{ +public: + typedef aero::CWindowImpl baseClass; + + DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW) + + void DoPaint(HDC hdc, RECT&) + { + if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) + SetSplitterPos(); + DrawSplitter(hdc); + } + + BEGIN_MSG_MAP(CSplitterWindowImpl) + CHAIN_MSG_MAP(baseClass) + MESSAGE_HANDLER(WM_SIZE, OnSize) + CHAIN_MSG_MAP(baseSplit) + FORWARD_NOTIFICATIONS() + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam != SIZE_MINIMIZED) + SetSplitterRect(); + + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// aero::CSplitterWindow - Implements an Aero drawing splitter window to be used as is + +template +class CSplitterWindowT : public aero::CSplitterWindowImpl, t_bVertical> +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_AeroSplitterWindow"), CS_DBLCLKS, COLOR_WINDOW) +}; + +typedef CSplitterWindowT CSplitterWindow; +typedef CSplitterWindowT CHorSplitterWindow; + +#endif // __ATLSPLIT_H__ + +}; // namespace aero +}; // namespace WTL + +#endif // __WTL_AERO_H__ + diff --git a/Console2.sln b/Console2.sln index 631d6814..92e8af80 100644 --- a/Console2.sln +++ b/Console2.sln @@ -14,6 +14,8 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 + Release aero|Win32 = Release aero|Win32 + Release aero|x64 = Release aero|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection @@ -22,6 +24,10 @@ Global {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Debug|Win32.Build.0 = Debug|Win32 {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Debug|x64.ActiveCfg = Debug|x64 {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Debug|x64.Build.0 = Debug|x64 + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Release aero|Win32.ActiveCfg = Release aero|Win32 + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Release aero|Win32.Build.0 = Release aero|Win32 + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Release aero|x64.ActiveCfg = Release aero|x64 + {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Release aero|x64.Build.0 = Release aero|x64 {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Release|Win32.ActiveCfg = Release|Win32 {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Release|Win32.Build.0 = Release|Win32 {69234D74-7133-48FF-8DDB-9901FFC4D7FF}.Release|x64.ActiveCfg = Release|x64 @@ -30,6 +36,10 @@ Global {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Debug|Win32.Build.0 = Debug|Win32 {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Debug|x64.ActiveCfg = Debug|x64 {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Debug|x64.Build.0 = Debug|x64 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release aero|Win32.ActiveCfg = Release aero|Win32 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release aero|Win32.Build.0 = Release aero|Win32 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release aero|x64.ActiveCfg = Release aero|x64 + {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release aero|x64.Build.0 = Release aero|x64 {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release|Win32.ActiveCfg = Release|Win32 {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release|Win32.Build.0 = Release|Win32 {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release|x64.ActiveCfg = Release|x64 diff --git a/ConsoleHook/ConsoleHook.vcproj b/ConsoleHook/ConsoleHook.vcproj index 26dd3176..44470360 100644 --- a/ConsoleHook/ConsoleHook.vcproj +++ b/ConsoleHook/ConsoleHook.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -385,6 +540,22 @@ UsePrecompiledHeader="1" /> + + + + + + GetText()); + Gdiplus::Graphics g(dc.m_hDC); + Gdiplus::Font font(dc.m_hDC); + Gdiplus::RectF rectF(0,0,1000,1000); + Gdiplus::RectF boundingBox; + Gdiplus::StringFormat stringFormat; + stringFormat.SetAlignment(Gdiplus::StringAlignmentNear); + stringFormat.SetLineAlignment(Gdiplus::StringAlignmentCenter); + stringFormat.SetFormatFlags(Gdiplus::StringFormatFlagsNoWrap|Gdiplus::StringFormatFlagsMeasureTrailingSpaces); + g.MeasureString( + szTitle, szTitleLen, + &font, + rectF, + &stringFormat, + &boundingBox); + + return (long)(boundingBox.Width); +#else + RECT rcText = { 0 }; + _CSTRING_NS::CString sText = this->GetText(); + dc.DrawText(sText, sText.GetLength(), &rcText, DT_SINGLELINE | DT_CALCRECT); + return rcText.right-rcText.left; +#endif + } _CSTRING_NS::CString GetToolTip() const { @@ -1386,8 +1415,8 @@ class ATL_NO_VTABLE CCustomTabCtrl : { m_dwState |= ectcMouseInWindow; - pT->UpdateLayout(); - this->Invalidate(); + //pT->UpdateLayout(); + //this->Invalidate(); // "OnMouseEnter" //... @@ -1562,10 +1591,10 @@ class ATL_NO_VTABLE CCustomTabCtrl : m_dwState &= ~ectcMouseInWindow; this->ClearCurrentHotTracking(false); - this->ClearCurrentMouseOverTracking(false); + this->ClearCurrentMouseOverTracking(true); - pT->UpdateLayout(); - this->Invalidate(); + //pT->UpdateLayout(); + //this->Invalidate(); return 0; } @@ -2318,10 +2347,7 @@ class ATL_NO_VTABLE CCustomTabCtrl : RECT rc = {xpos, 0, xpos, height}; if( pItem->UsingText() ) { - RECT rcText = { 0 }; - _CSTRING_NS::CString sText = pItem->GetText(); - dc.DrawText(sText, sText.GetLength(), &rcText, DT_SINGLELINE | DT_CALCRECT); - rc.right += (rcText.right-rcText.left) + (m_settings.iPadding*2); + rc.right += pItem->GetTextSize(dc) + (m_settings.iPadding*2); } pItem->SetRect(rc); xpos += (rc.right-rc.left) + m_settings.iMargin; diff --git a/TabbingFramework/DotNetTabCtrl.h b/TabbingFramework/DotNetTabCtrl.h index 4460b640..fc9ca9d6 100644 --- a/TabbingFramework/DotNetTabCtrl.h +++ b/TabbingFramework/DotNetTabCtrl.h @@ -1048,10 +1048,7 @@ class CDotNetTabCtrlImpl : } if(pItem->UsingText()) { - RECT rcText = {0}; - _CSTRING_NS::CString sText = pItem->GetText(); - dc.DrawText(sText, sText.GetLength(), &rcText, DT_SINGLELINE | DT_CALCRECT); - rcItem.right += (rcText.right - rcText.left) + (m_settings.iPadding * 2); + rcItem.right += pItem->GetTextSize(dc) + (m_settings.iPadding * 2); } rcItem.right += m_settings.iMargin; pItem->SetRect(rcItem); @@ -1197,10 +1194,7 @@ class CDotNetTabCtrlImpl : } if(pItem->UsingText()) { - RECT rcText = {0}; - _CSTRING_NS::CString sText = pItem->GetText(); - dc.DrawText(sText, sText.GetLength(), &rcText, DT_SINGLELINE | DT_CALCRECT); - rcItem.right += (rcText.right - rcText.left) + (m_settings.iPadding * 2); + rcItem.right += pItem->GetTextSize(dc) + (m_settings.iPadding * 2); } rcItem.right += m_settings.iMargin; pItem->SetRect(rcItem); diff --git a/TabbingFramework/TabbedFrame.h b/TabbingFramework/TabbedFrame.h index 6f817bab..082f44e0 100644 --- a/TabbingFramework/TabbedFrame.h +++ b/TabbingFramework/TabbedFrame.h @@ -845,8 +845,14 @@ class CCustomTabOwnerImpl template < class T, +#ifdef _USE_AERO + class TTabCtrl = CAeroTabCtrl, + class TBase = aero::CFrameWindowImpl +#else class TTabCtrl = CDotNetTabCtrl, - class TBase = WTL::CFrameWindowImpl > + class TBase = WTL::CFrameWindowImpl +#endif +> class CTabbedFrameImpl : public TBase, public CCustomTabOwnerImpl From 409954d209b380aa0c8750578b4e68f54849b3c6 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 14 Aug 2010 01:20:34 +0200 Subject: [PATCH 002/207] WTL modified for AERO --- .gitmodules | 3 - wtl | 1 - wtl/wtl/include/atlapp.h | 1688 ++++++ wtl/wtl/include/atlcrack.h | 2380 +++++++++ wtl/wtl/include/atlctrls.h | 10039 +++++++++++++++++++++++++++++++++++ wtl/wtl/include/atlctrlw.h | 4161 +++++++++++++++ wtl/wtl/include/atlctrlx.h | 4827 +++++++++++++++++ wtl/wtl/include/atlddx.h | 624 +++ wtl/wtl/include/atldlgs.h | 6212 ++++++++++++++++++++++ wtl/wtl/include/atlfind.h | 1036 ++++ wtl/wtl/include/atlframe.h | 3476 ++++++++++++ wtl/wtl/include/atlgdi.h | 3850 ++++++++++++++ wtl/wtl/include/atlmisc.h | 4021 ++++++++++++++ wtl/wtl/include/atlprint.h | 1113 ++++ wtl/wtl/include/atlres.h | 262 + wtl/wtl/include/atlresce.h | 93 + wtl/wtl/include/atlscrl.h | 2015 +++++++ wtl/wtl/include/atlsplit.h | 892 ++++ wtl/wtl/include/atltheme.h | 1218 +++++ wtl/wtl/include/atluser.h | 1162 ++++ wtl/wtl/include/atlwince.h | 3010 +++++++++++ wtl/wtl/include/atlwinx.h | 529 ++ 22 files changed, 52608 insertions(+), 4 deletions(-) delete mode 100644 .gitmodules delete mode 160000 wtl create mode 100644 wtl/wtl/include/atlapp.h create mode 100644 wtl/wtl/include/atlcrack.h create mode 100644 wtl/wtl/include/atlctrls.h create mode 100644 wtl/wtl/include/atlctrlw.h create mode 100644 wtl/wtl/include/atlctrlx.h create mode 100644 wtl/wtl/include/atlddx.h create mode 100644 wtl/wtl/include/atldlgs.h create mode 100644 wtl/wtl/include/atlfind.h create mode 100644 wtl/wtl/include/atlframe.h create mode 100644 wtl/wtl/include/atlgdi.h create mode 100644 wtl/wtl/include/atlmisc.h create mode 100644 wtl/wtl/include/atlprint.h create mode 100644 wtl/wtl/include/atlres.h create mode 100644 wtl/wtl/include/atlresce.h create mode 100644 wtl/wtl/include/atlscrl.h create mode 100644 wtl/wtl/include/atlsplit.h create mode 100644 wtl/wtl/include/atltheme.h create mode 100644 wtl/wtl/include/atluser.h create mode 100644 wtl/wtl/include/atlwince.h create mode 100644 wtl/wtl/include/atlwinx.h diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index d4a11155..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "wtl"] - path = wtl - url = git://github.com/akirill/wtl.git diff --git a/wtl b/wtl deleted file mode 160000 index b3e98330..00000000 --- a/wtl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b3e98330514b0019d96eeeb7e31b2706064b11b9 diff --git a/wtl/wtl/include/atlapp.h b/wtl/wtl/include/atlapp.h new file mode 100644 index 00000000..b62e0970 --- /dev/null +++ b/wtl/wtl/include/atlapp.h @@ -0,0 +1,1688 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLAPP_H__ +#define __ATLAPP_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLBASE_H__ + #error atlapp.h requires atlbase.h to be included first +#endif + +#ifndef _WIN32_WCE + #if (WINVER < 0x0400) + #error WTL requires Windows version 4.0 or higher + #endif + + #if (_WIN32_IE < 0x0300) + #error WTL requires IE version 3.0 or higher + #endif +#endif + +#ifdef _ATL_NO_COMMODULE + #error WTL requires that _ATL_NO_COMMODULE is not defined +#endif // _ATL_NO_COMMODULE + +#if defined(_WIN32_WCE) && defined(_ATL_MIN_CRT) + #pragma message("Warning: WTL for Windows CE doesn't use _ATL_MIN_CRT") +#endif // defined(_WIN32_WCE) && defined(_ATL_MIN_CRT) + +#include +#if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE) + #include // for _beginthreadex +#endif + +#if (_ATL_VER < 0x0800) && !defined(_DEBUG) + #include +#endif + +#include +#ifndef _WIN32_WCE +#pragma comment(lib, "comctl32.lib") +#endif // !_WIN32_WCE + +#ifndef _WIN32_WCE + #include "atlres.h" +#else // CE specific + #include "atlresce.h" +#endif // _WIN32_WCE + +// We need to disable this warning because of template class arguments +#pragma warning(disable: 4127) + + +/////////////////////////////////////////////////////////////////////////////// +// WTL version number + +#define _WTL_VER 0x0800 + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CMessageFilter +// CIdleHandler +// CMessageLoop +// +// CAppModule +// CServerAppModule +// +// Global functions: +// AtlGetDefaultGuiFont() +// AtlCreateBoldFont() +// AtlInitCommonControls() + + +/////////////////////////////////////////////////////////////////////////////// +// Global support for Windows CE + +#ifdef _WIN32_WCE + +#ifndef SW_SHOWDEFAULT + #define SW_SHOWDEFAULT SW_SHOWNORMAL +#endif // !SW_SHOWDEFAULT + +// These get's OR-ed in a constant and will have no effect. +// Defining them reduces the number of #ifdefs required for CE. +#define LR_DEFAULTSIZE 0 +#define LR_LOADFROMFILE 0 + +#ifndef SM_CXCURSOR + #define SM_CXCURSOR 13 +#endif +#ifndef SM_CYCURSOR + #define SM_CYCURSOR 14 +#endif + +inline BOOL IsMenu(HMENU hMenu) +{ + MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; + ::SetLastError(0); + BOOL bRet = ::GetMenuItemInfo(hMenu, 0, TRUE, &mii); + if(!bRet) + bRet = (::GetLastError() != ERROR_INVALID_MENU_HANDLE) ? TRUE : FALSE; + return bRet; +} + +#if (_WIN32_WCE >= 410) +extern "C" void WINAPI ListView_SetItemSpacing(HWND hwndLV, int iHeight); +#endif // (_WIN32_WCE >= 410) + +inline int MulDiv(IN int nNumber, IN int nNumerator, IN int nDenominator) +{ + __int64 multiple = nNumber * nNumerator; + return static_cast(multiple / nDenominator); +} + +#if (_ATL_VER >= 0x0800) + +#ifndef _WTL_KEEP_WS_OVERLAPPEDWINDOW + #ifdef WS_OVERLAPPEDWINDOW + #undef WS_OVERLAPPEDWINDOW + #define WS_OVERLAPPEDWINDOW 0 + #endif // WS_OVERLAPPEDWINDOW +#endif // !_WTL_KEEP_WS_OVERLAPPEDWINDOW + +#ifndef RDW_FRAME + #define RDW_FRAME 0 +#endif // !RDW_FRAME + +#ifndef WM_WINDOWPOSCHANGING + #define WM_WINDOWPOSCHANGING 0 +#endif // !WM_WINDOWPOSCHANGING + +#define FreeResource(x) +#define UnlockResource(x) + +namespace ATL +{ + inline HRESULT CComModule::RegisterClassObjects(DWORD /*dwClsContext*/, DWORD /*dwFlags*/) throw() + { return E_NOTIMPL; } + inline HRESULT CComModule::RevokeClassObjects() throw() + { return E_NOTIMPL; } +}; // namespace ATL + +#ifndef lstrlenW + #define lstrlenW (int)ATL::lstrlenW +#endif // lstrlenW + +inline int WINAPI lstrlenA(LPCSTR lpszString) +{ return ATL::lstrlenA(lpszString); } + +#ifdef lstrcpyn + #undef lstrcpyn + #define lstrcpyn ATL::lstrcpynW +#endif // lstrcpyn + +#ifndef SetWindowLongPtrW + inline LONG_PTR tmp_SetWindowLongPtrW( HWND hWnd, int nIndex, LONG_PTR dwNewLong ) + { + return( ::SetWindowLongW( hWnd, nIndex, LONG( dwNewLong ) ) ); + } + #define SetWindowLongPtrW tmp_SetWindowLongPtrW +#endif + +#ifndef GetWindowLongPtrW + inline LONG_PTR tmp_GetWindowLongPtrW( HWND hWnd, int nIndex ) + { + return( ::GetWindowLongW( hWnd, nIndex ) ); + } + #define GetWindowLongPtrW tmp_GetWindowLongPtrW +#endif + +#ifndef LongToPtr + #define LongToPtr(x) ((void*)x) +#endif + +#ifndef PtrToInt + #define PtrToInt( p ) ((INT)(INT_PTR) (p) ) +#endif + +#else // !(_ATL_VER >= 0x0800) + +#ifdef lstrlenW + #undef lstrlenW + #define lstrlenW (int)::wcslen +#endif // lstrlenW + +#define lstrlenA (int)strlen + +#ifndef lstrcpyn + inline LPTSTR lstrcpyn(LPTSTR lpstrDest, LPCTSTR lpstrSrc, int nLength) + { + if(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0) + return NULL; + int nLen = min(lstrlen(lpstrSrc), nLength - 1); + LPTSTR lpstrRet = (LPTSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(TCHAR)); + lpstrDest[nLen] = 0; + return lpstrRet; + } +#endif // !lstrcpyn + +#ifndef lstrcpynW + inline LPWSTR lstrcpynW(LPWSTR lpstrDest, LPCWSTR lpstrSrc, int nLength) + { + return lstrcpyn(lpstrDest, lpstrSrc, nLength); // WinCE is Unicode only + } +#endif // !lstrcpynW + +#ifndef lstrcpynA + inline LPSTR lstrcpynA(LPSTR lpstrDest, LPCSTR lpstrSrc, int nLength) + { + if(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0) + return NULL; + int nLen = min(lstrlenA(lpstrSrc), nLength - 1); + LPSTR lpstrRet = (LPSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(char)); + lpstrDest[nLen] = 0; + return lpstrRet; + } +#endif // !lstrcpyn + +#ifdef TrackPopupMenu + #undef TrackPopupMenu +#endif // TrackPopupMenu + +#define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd) \ +static CWndClassInfo& GetWndClassInfo() \ +{ \ + static CWndClassInfo wc = \ + { \ + { style, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \ + }; \ + return wc; \ +} + +#ifndef _MAX_FNAME + #define _MAX_FNAME _MAX_PATH +#endif // _MAX_FNAME + +#if (_WIN32_WCE < 400) + #define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i))) +#endif // (_WIN32_WCE < 400) + +#if (_WIN32_WCE < 410) + #define WHEEL_PAGESCROLL (UINT_MAX) + #define WHEEL_DELTA 120 +#endif // (_WIN32_WCE < 410) + +#ifdef DrawIcon + #undef DrawIcon +#endif + +#ifndef VARCMP_LT + #define VARCMP_LT 0 +#endif +#ifndef VARCMP_EQ + #define VARCMP_EQ 1 +#endif +#ifndef VARCMP_GT + #define VARCMP_GT 2 +#endif +#ifndef VARCMP_NULL + #define VARCMP_NULL 3 +#endif + +#ifndef RDW_ALLCHILDREN + #define RDW_ALLCHILDREN 0 +#endif + +#endif // !(_ATL_VER >= 0x0800) + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// Global support for using original VC++ 6.0 headers with WTL + +#ifndef _ATL_NO_OLD_HEADERS_WIN64 +#if !defined(_WIN64) && (_ATL_VER < 0x0700) + + #ifndef PSM_INSERTPAGE + #define PSM_INSERTPAGE (WM_USER + 119) + #endif // !PSM_INSERTPAGE + + #ifndef GetClassLongPtr + #define GetClassLongPtrA GetClassLongA + #define GetClassLongPtrW GetClassLongW + #ifdef UNICODE + #define GetClassLongPtr GetClassLongPtrW + #else + #define GetClassLongPtr GetClassLongPtrA + #endif // !UNICODE + #endif // !GetClassLongPtr + + #ifndef GCLP_HICONSM + #define GCLP_HICONSM (-34) + #endif // !GCLP_HICONSM + + #ifndef GetWindowLongPtr + #define GetWindowLongPtrA GetWindowLongA + #define GetWindowLongPtrW GetWindowLongW + #ifdef UNICODE + #define GetWindowLongPtr GetWindowLongPtrW + #else + #define GetWindowLongPtr GetWindowLongPtrA + #endif // !UNICODE + #endif // !GetWindowLongPtr + + #ifndef SetWindowLongPtr + #define SetWindowLongPtrA SetWindowLongA + #define SetWindowLongPtrW SetWindowLongW + #ifdef UNICODE + #define SetWindowLongPtr SetWindowLongPtrW + #else + #define SetWindowLongPtr SetWindowLongPtrA + #endif // !UNICODE + #endif // !SetWindowLongPtr + + #ifndef GWLP_WNDPROC + #define GWLP_WNDPROC (-4) + #endif + #ifndef GWLP_HINSTANCE + #define GWLP_HINSTANCE (-6) + #endif + #ifndef GWLP_HWNDPARENT + #define GWLP_HWNDPARENT (-8) + #endif + #ifndef GWLP_USERDATA + #define GWLP_USERDATA (-21) + #endif + #ifndef GWLP_ID + #define GWLP_ID (-12) + #endif + + #ifndef DWLP_MSGRESULT + #define DWLP_MSGRESULT 0 + #endif + + typedef long LONG_PTR; + typedef unsigned long ULONG_PTR; + typedef ULONG_PTR DWORD_PTR; + + #ifndef HandleToUlong + #define HandleToUlong( h ) ((ULONG)(ULONG_PTR)(h) ) + #endif + #ifndef HandleToLong + #define HandleToLong( h ) ((LONG)(LONG_PTR) (h) ) + #endif + #ifndef LongToHandle + #define LongToHandle( h) ((HANDLE)(LONG_PTR) (h)) + #endif + #ifndef PtrToUlong + #define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) ) + #endif + #ifndef PtrToLong + #define PtrToLong( p ) ((LONG)(LONG_PTR) (p) ) + #endif + #ifndef PtrToUint + #define PtrToUint( p ) ((UINT)(UINT_PTR) (p) ) + #endif + #ifndef PtrToInt + #define PtrToInt( p ) ((INT)(INT_PTR) (p) ) + #endif + #ifndef PtrToUshort + #define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) ) + #endif + #ifndef PtrToShort + #define PtrToShort( p ) ((short)(LONG_PTR)(p) ) + #endif + #ifndef IntToPtr + #define IntToPtr( i ) ((VOID *)(INT_PTR)((int)i)) + #endif + #ifndef UIntToPtr + #define UIntToPtr( ui ) ((VOID *)(UINT_PTR)((unsigned int)ui)) + #endif + #ifndef LongToPtr + #define LongToPtr( l ) ((VOID *)(LONG_PTR)((long)l)) + #endif + #ifndef ULongToPtr + #define ULongToPtr( ul ) ((VOID *)(ULONG_PTR)((unsigned long)ul)) + #endif + +#endif // !defined(_WIN64) && (_ATL_VER < 0x0700) +#endif // !_ATL_NO_OLD_HEADERS_WIN64 + + +/////////////////////////////////////////////////////////////////////////////// +// Global support for SecureHelper functions + +#ifndef _TRUNCATE + #define _TRUNCATE ((size_t)-1) +#endif + +#ifndef _ERRCODE_DEFINED + #define _ERRCODE_DEFINED + typedef int errno_t; +#endif + +#ifndef _SECURECRT_ERRCODE_VALUES_DEFINED + #define _SECURECRT_ERRCODE_VALUES_DEFINED + #define EINVAL 22 + #define STRUNCATE 80 +#endif + +#ifndef _countof + #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Miscellaneous global support + +// define useful macros from winuser.h +#ifndef IS_INTRESOURCE + #define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0) +#endif // IS_INTRESOURCE + +// protect template members from windowsx.h macros +#ifdef _INC_WINDOWSX + #undef SubclassWindow +#endif // _INC_WINDOWSX + +// define useful macros from windowsx.h +#ifndef GET_X_LPARAM + #define GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam)) +#endif +#ifndef GET_Y_LPARAM + #define GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam)) +#endif + +// Dummy structs for compiling with /CLR +#if (_MSC_VER >= 1300) && defined(_MANAGED) + __if_not_exists(_IMAGELIST::_IMAGELIST) { struct _IMAGELIST { }; } + __if_not_exists(_TREEITEM::_TREEITEM) { struct _TREEITEM { }; } + __if_not_exists(_PSP::_PSP) { struct _PSP { }; } +#endif + +// Define ATLVERIFY macro for ATL3 +#if (_ATL_VER < 0x0700) + #ifndef ATLVERIFY + #ifdef _DEBUG + #define ATLVERIFY(expr) ATLASSERT(expr) + #else + #define ATLVERIFY(expr) (expr) + #endif // DEBUG + #endif // ATLVERIFY +#endif // (_ATL_VER < 0x0700) + +// Forward declaration for ATL3 fix +#if (_ATL_VER < 0x0700) && defined(_ATL_DLL) && !defined(_WIN32_WCE) + namespace ATL { HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); }; +#endif + + +namespace WTL +{ + +#if (_ATL_VER >= 0x0700) + DECLARE_TRACE_CATEGORY(atlTraceUI); + #ifdef _DEBUG + __declspec(selectany) ATL::CTraceCategory atlTraceUI(_T("atlTraceUI")); + #endif // _DEBUG +#else // !(_ATL_VER >= 0x0700) + enum wtlTraceFlags + { + atlTraceUI = 0x10000000 + }; +#endif // !(_ATL_VER >= 0x0700) + +// Windows version helper +inline bool AtlIsOldWindows() +{ + OSVERSIONINFO ovi = { 0 }; + ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + BOOL bRet = ::GetVersionEx(&ovi); + return (!bRet || !((ovi.dwMajorVersion >= 5) || (ovi.dwMajorVersion == 4 && ovi.dwMinorVersion >= 90))); +} + +// default GUI font helper +inline HFONT AtlGetDefaultGuiFont() +{ +#ifndef _WIN32_WCE + return (HFONT)::GetStockObject(DEFAULT_GUI_FONT); +#else // CE specific + return (HFONT)::GetStockObject(SYSTEM_FONT); +#endif // _WIN32_WCE +} + +// bold font helper (NOTE: Caller owns the font, and should destroy it when done using it) +inline HFONT AtlCreateBoldFont(HFONT hFont = NULL) +{ + if(hFont == NULL) + hFont = AtlGetDefaultGuiFont(); + ATLASSERT(hFont != NULL); + HFONT hFontBold = NULL; + LOGFONT lf = { 0 }; + if(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT)) + { + lf.lfWeight = FW_BOLD; + hFontBold = ::CreateFontIndirect(&lf); + ATLASSERT(hFontBold != NULL); + } + else + { + ATLASSERT(FALSE); + } + return hFontBold; +} + +// Common Controls initialization helper +inline BOOL AtlInitCommonControls(DWORD dwFlags) +{ + INITCOMMONCONTROLSEX iccx = { sizeof(INITCOMMONCONTROLSEX), dwFlags }; + BOOL bRet = ::InitCommonControlsEx(&iccx); + ATLASSERT(bRet); + return bRet; +} + + +/////////////////////////////////////////////////////////////////////////////// +// RunTimeHelper - helper functions for Windows version and structure sizes + +// Not for Windows CE +#if defined(_WIN32_WCE) && !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) + #define _WTL_NO_RUNTIME_STRUCT_SIZE +#endif + +#ifndef _WTL_NO_RUNTIME_STRUCT_SIZE + +#ifndef _SIZEOF_STRUCT + #define _SIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) +#endif + +#if (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE) + #define REBARBANDINFO_V6_SIZE _SIZEOF_STRUCT(REBARBANDINFO, cxHeader) +#endif // (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE) + +#if (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE) + #define LVGROUP_V5_SIZE _SIZEOF_STRUCT(LVGROUP, uAlign) +#endif // (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE) + +#if (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE) + #define LVTILEINFO_V5_SIZE _SIZEOF_STRUCT(LVTILEINFO, puColumns) +#endif // (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE) + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE) + #define MCHITTESTINFO_V1_SIZE _SIZEOF_STRUCT(MCHITTESTINFO, st) +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE) + +#if !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE) + #define NONCLIENTMETRICS_V1_SIZE _SIZEOF_STRUCT(NONCLIENTMETRICS, lfMessageFont) +#endif // !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE) + +#endif // !_WTL_NO_RUNTIME_STRUCT_SIZE + +namespace RunTimeHelper +{ +#ifndef _WIN32_WCE + inline bool IsCommCtrl6() + { + DWORD dwMajor = 0, dwMinor = 0; + HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); + return (SUCCEEDED(hRet) && (dwMajor >= 6)); + } + + inline bool IsVista() + { + OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; + BOOL bRet = ::GetVersionEx(&ovi); + return ((bRet != FALSE) && (ovi.dwMajorVersion >= 6)); + } +#endif // !_WIN32_WCE + + inline int SizeOf_REBARBANDINFO() + { + int nSize = sizeof(REBARBANDINFO); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + if(!(IsVista() && IsCommCtrl6())) + nSize = REBARBANDINFO_V6_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + return nSize; + } + +#if (_WIN32_WINNT >= 0x501) + inline int SizeOf_LVGROUP() + { + int nSize = sizeof(LVGROUP); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + if(!IsVista()) + nSize = LVGROUP_V5_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + return nSize; + } + + inline int SizeOf_LVTILEINFO() + { + int nSize = sizeof(LVTILEINFO); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + if(!IsVista()) + nSize = LVTILEINFO_V5_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) + return nSize; + } +#endif // (_WIN32_WINNT >= 0x501) + + inline int SizeOf_MCHITTESTINFO() + { + int nSize = sizeof(MCHITTESTINFO); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + if(!(IsVista() && IsCommCtrl6())) + nSize = MCHITTESTINFO_V1_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + return nSize; + } + +#ifndef _WIN32_WCE + inline int SizeOf_NONCLIENTMETRICS() + { + int nSize = sizeof(NONCLIENTMETRICS); +#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600) + if(!IsVista()) + nSize = NONCLIENTMETRICS_V1_SIZE; +#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600) + return nSize; + } +#endif // !_WIN32_WCE +}; + + +/////////////////////////////////////////////////////////////////////////////// +// ModuleHelper - helper functions for ATL3 and ATL7 module classes + +namespace ModuleHelper +{ + inline HINSTANCE GetModuleInstance() + { +#if (_ATL_VER >= 0x0700) + return ATL::_AtlBaseModule.GetModuleInstance(); +#else // !(_ATL_VER >= 0x0700) + return ATL::_pModule->GetModuleInstance(); +#endif // !(_ATL_VER >= 0x0700) + } + + inline HINSTANCE GetResourceInstance() + { +#if (_ATL_VER >= 0x0700) + return ATL::_AtlBaseModule.GetResourceInstance(); +#else // !(_ATL_VER >= 0x0700) + return ATL::_pModule->GetResourceInstance(); +#endif // !(_ATL_VER >= 0x0700) + } + + inline void AddCreateWndData(ATL::_AtlCreateWndData* pData, void* pObject) + { +#if (_ATL_VER >= 0x0700) + ATL::_AtlWinModule.AddCreateWndData(pData, pObject); +#else // !(_ATL_VER >= 0x0700) + ATL::_pModule->AddCreateWndData(pData, pObject); +#endif // !(_ATL_VER >= 0x0700) + } + + inline void* ExtractCreateWndData() + { +#if (_ATL_VER >= 0x0700) + return ATL::_AtlWinModule.ExtractCreateWndData(); +#else // !(_ATL_VER >= 0x0700) + return ATL::_pModule->ExtractCreateWndData(); +#endif // !(_ATL_VER >= 0x0700) + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// SecureHelper - helper functions for VS2005 secure CRT + +namespace SecureHelper +{ + inline void strcpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc) + { +#if _SECURE_ATL + ATL::Checked::strcpy_s(lpstrDest, cchDest, lpstrSrc); +#else + if(cchDest > (size_t)lstrlenA(lpstrSrc)) + ATLVERIFY(lstrcpyA(lpstrDest, lpstrSrc) != NULL); + else + ATLASSERT(FALSE); +#endif + } + + inline void strcpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc) + { +#if _SECURE_ATL + ATL::Checked::wcscpy_s(lpstrDest, cchDest, lpstrSrc); +#else + if(cchDest > (size_t)lstrlenW(lpstrSrc)) + ATLVERIFY(lstrcpyW(lpstrDest, lpstrSrc) != NULL); + else + ATLASSERT(FALSE); +#endif + } + + inline void strcpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc) + { +#ifdef _UNICODE + strcpyW_x(lpstrDest, cchDest, lpstrSrc); +#else + strcpyA_x(lpstrDest, cchDest, lpstrSrc); +#endif + } + + inline errno_t strncpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc, size_t cchCount) + { +#if _SECURE_ATL + return ATL::Checked::strncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount); +#else + errno_t nRet = 0; + if(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL) + { + nRet = EINVAL; + } + else if(cchCount == _TRUNCATE) + { + cchCount = min(cchDest - 1, size_t(lstrlenA(lpstrSrc))); + nRet = STRUNCATE; + } + else if(cchDest <= cchCount) + { + lpstrDest[0] = 0; + nRet = EINVAL; + } + if(nRet == 0 || nRet == STRUNCATE) + nRet = (lstrcpynA(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL; + ATLASSERT(nRet == 0 || nRet == STRUNCATE); + return nRet; +#endif + } + + inline errno_t strncpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc, size_t cchCount) + { +#if _SECURE_ATL + return ATL::Checked::wcsncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount); +#else + errno_t nRet = 0; + if(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL) + { + nRet = EINVAL; + } + else if(cchCount == _TRUNCATE) + { + cchCount = min(cchDest - 1, size_t(lstrlenW(lpstrSrc))); + nRet = STRUNCATE; + } + else if(cchDest <= cchCount) + { + lpstrDest[0] = 0; + nRet = EINVAL; + } + if(nRet == 0 || nRet == STRUNCATE) + nRet = (lstrcpynW(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL; + ATLASSERT(nRet == 0 || nRet == STRUNCATE); + return nRet; +#endif + } + + inline errno_t strncpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc, size_t cchCount) + { +#ifdef _UNICODE + return strncpyW_x(lpstrDest, cchDest, lpstrSrc, cchCount); +#else + return strncpyA_x(lpstrDest, cchDest, lpstrSrc, cchCount); +#endif + } + + inline void strcatA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc) + { +#if _SECURE_ATL + ATL::Checked::strcat_s(lpstrDest, cchDest, lpstrSrc); +#else + if(cchDest > (size_t)lstrlenA(lpstrSrc)) + ATLVERIFY(lstrcatA(lpstrDest, lpstrSrc) != NULL); + else + ATLASSERT(FALSE); +#endif + } + + inline void strcatW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc) + { +#if _SECURE_ATL + ATL::Checked::wcscat_s(lpstrDest, cchDest, lpstrSrc); +#else + if(cchDest > (size_t)lstrlenW(lpstrSrc)) + ATLVERIFY(lstrcatW(lpstrDest, lpstrSrc) != NULL); + else + ATLASSERT(FALSE); +#endif + } + + inline void strcat_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc) + { +#ifdef _UNICODE + strcatW_x(lpstrDest, cchDest, lpstrSrc); +#else + strcatA_x(lpstrDest, cchDest, lpstrSrc); +#endif + } + + inline void memcpy_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc) + { +#if _SECURE_ATL + ATL::Checked::memcpy_s(pDest, cbDest, pSrc, cbSrc); +#else + if(cbDest >= cbSrc) + memcpy(pDest, pSrc, cbSrc); + else + ATLASSERT(FALSE); +#endif + } + + inline void memmove_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc) + { +#if _SECURE_ATL + ATL::Checked::memmove_s(pDest, cbDest, pSrc, cbSrc); +#else + if(cbDest >= cbSrc) + memmove(pDest, pSrc, cbSrc); + else + ATLASSERT(FALSE); +#endif + } + + inline int vsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args) + { +#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE) + return _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args); +#else + cchBuff; // Avoid unused argument warning + return _vstprintf(lpstrBuff, lpstrFormat, args); +#endif + } + + inline int wvsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args) + { +#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE) + return _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args); +#else + cchBuff; // Avoid unused argument warning + return ::wvsprintf(lpstrBuff, lpstrFormat, args); +#endif + } + + inline int sprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...) + { + va_list args; + va_start(args, lpstrFormat); + int nRes = vsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args); + va_end(args); + return nRes; + } + + inline int wsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...) + { + va_list args; + va_start(args, lpstrFormat); + int nRes = wvsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args); + va_end(args); + return nRes; + } +}; // namespace SecureHelper + + +/////////////////////////////////////////////////////////////////////////////// +// CMessageFilter - Interface for message filter support + +class CMessageFilter +{ +public: + virtual BOOL PreTranslateMessage(MSG* pMsg) = 0; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CIdleHandler - Interface for idle processing + +class CIdleHandler +{ +public: + virtual BOOL OnIdle() = 0; +}; + +#ifndef _ATL_NO_OLD_NAMES + // for compatilibility with old names only + typedef CIdleHandler CUpdateUIObject; + #define DoUpdate OnIdle +#endif // !_ATL_NO_OLD_NAMES + + +/////////////////////////////////////////////////////////////////////////////// +// CMessageLoop - message loop implementation + +class CMessageLoop +{ +public: + ATL::CSimpleArray m_aMsgFilter; + ATL::CSimpleArray m_aIdleHandler; + MSG m_msg; + +// Message filter operations + BOOL AddMessageFilter(CMessageFilter* pMessageFilter) + { + return m_aMsgFilter.Add(pMessageFilter); + } + + BOOL RemoveMessageFilter(CMessageFilter* pMessageFilter) + { + return m_aMsgFilter.Remove(pMessageFilter); + } + +// Idle handler operations + BOOL AddIdleHandler(CIdleHandler* pIdleHandler) + { + return m_aIdleHandler.Add(pIdleHandler); + } + + BOOL RemoveIdleHandler(CIdleHandler* pIdleHandler) + { + return m_aIdleHandler.Remove(pIdleHandler); + } + +#ifndef _ATL_NO_OLD_NAMES + // for compatilibility with old names only + BOOL AddUpdateUI(CIdleHandler* pIdleHandler) + { + ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIObject and AddUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\n")); + return AddIdleHandler(pIdleHandler); + } + + BOOL RemoveUpdateUI(CIdleHandler* pIdleHandler) + { + ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIObject and RemoveUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\n")); + return RemoveIdleHandler(pIdleHandler); + } +#endif // !_ATL_NO_OLD_NAMES + +// message loop + int Run() + { + BOOL bDoIdle = TRUE; + int nIdleCount = 0; + BOOL bRet; + + for(;;) + { + while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE)) + { + if(!OnIdle(nIdleCount++)) + bDoIdle = FALSE; + } + + bRet = ::GetMessage(&m_msg, NULL, 0, 0); + + if(bRet == -1) + { + ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n")); + continue; // error, don't process + } + else if(!bRet) + { + ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n")); + break; // WM_QUIT, exit message loop + } + + if(!PreTranslateMessage(&m_msg)) + { + ::TranslateMessage(&m_msg); + ::DispatchMessage(&m_msg); + } + + if(IsIdleMessage(&m_msg)) + { + bDoIdle = TRUE; + nIdleCount = 0; + } + } + + return (int)m_msg.wParam; + } + + static BOOL IsIdleMessage(MSG* pMsg) + { + // These messages should NOT cause idle processing + switch(pMsg->message) + { + case WM_MOUSEMOVE: +#ifndef _WIN32_WCE + case WM_NCMOUSEMOVE: +#endif // !_WIN32_WCE + case WM_PAINT: + case 0x0118: // WM_SYSTIMER (caret blink) + return FALSE; + } + + return TRUE; + } + +// Overrideables + // Override to change message filtering + virtual BOOL PreTranslateMessage(MSG* pMsg) + { + // loop backwards + for(int i = m_aMsgFilter.GetSize() - 1; i >= 0; i--) + { + CMessageFilter* pMessageFilter = m_aMsgFilter[i]; + if(pMessageFilter != NULL && pMessageFilter->PreTranslateMessage(pMsg)) + return TRUE; + } + return FALSE; // not translated + } + + // override to change idle processing + virtual BOOL OnIdle(int /*nIdleCount*/) + { + for(int i = 0; i < m_aIdleHandler.GetSize(); i++) + { + CIdleHandler* pIdleHandler = m_aIdleHandler[i]; + if(pIdleHandler != NULL) + pIdleHandler->OnIdle(); + } + return FALSE; // don't continue + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CStaticDataInitCriticalSectionLock and CWindowCreateCriticalSectionLock +// internal classes to manage critical sections for both ATL3 and ATL7 + +class CStaticDataInitCriticalSectionLock +{ +public: +#if (_ATL_VER >= 0x0700) + ATL::CComCritSecLock m_cslock; + + CStaticDataInitCriticalSectionLock() : m_cslock(ATL::_pAtlModule->m_csStaticDataInitAndTypeInfo, false) + { } +#endif // (_ATL_VER >= 0x0700) + + HRESULT Lock() + { +#if (_ATL_VER >= 0x0700) + return m_cslock.Lock(); +#else // !(_ATL_VER >= 0x0700) + ::EnterCriticalSection(&ATL::_pModule->m_csStaticDataInit); + return S_OK; +#endif // !(_ATL_VER >= 0x0700) + } + + void Unlock() + { +#if (_ATL_VER >= 0x0700) + m_cslock.Unlock(); +#else // !(_ATL_VER >= 0x0700) + ::LeaveCriticalSection(&ATL::_pModule->m_csStaticDataInit); +#endif // !(_ATL_VER >= 0x0700) + } +}; + + +class CWindowCreateCriticalSectionLock +{ +public: +#if (_ATL_VER >= 0x0700) + ATL::CComCritSecLock m_cslock; + + CWindowCreateCriticalSectionLock() : m_cslock(ATL::_AtlWinModule.m_csWindowCreate, false) + { } +#endif // (_ATL_VER >= 0x0700) + + HRESULT Lock() + { +#if (_ATL_VER >= 0x0700) + return m_cslock.Lock(); +#else // !(_ATL_VER >= 0x0700) + ::EnterCriticalSection(&ATL::_pModule->m_csWindowCreate); + return S_OK; +#endif // !(_ATL_VER >= 0x0700) + } + + void Unlock() + { +#if (_ATL_VER >= 0x0700) + m_cslock.Unlock(); +#else // !(_ATL_VER >= 0x0700) + ::LeaveCriticalSection(&ATL::_pModule->m_csWindowCreate); +#endif // !(_ATL_VER >= 0x0700) + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CTempBuffer - helper class for stack allocations for ATL3 + +#ifndef _WTL_STACK_ALLOC_THRESHOLD + #define _WTL_STACK_ALLOC_THRESHOLD 512 +#endif + +#if (_ATL_VER >= 0x0700) + +using ATL::CTempBuffer; + +#else // !(_ATL_VER >= 0x0700) + +#ifndef SIZE_MAX + #ifdef _WIN64 + #define SIZE_MAX _UI64_MAX + #else + #define SIZE_MAX UINT_MAX + #endif +#endif + +#pragma warning(disable: 4284) // warning for operator -> + +template +class CTempBuffer +{ +public: + CTempBuffer() : m_p(NULL) + { + } + + CTempBuffer(size_t nElements) : m_p(NULL) + { + Allocate(nElements); + } + + ~CTempBuffer() + { + if(m_p != reinterpret_cast(m_abFixedBuffer)) + free(m_p); + } + + operator T*() const + { + return m_p; + } + + T* operator ->() const + { + ATLASSERT(m_p != NULL); + return m_p; + } + + T* Allocate(size_t nElements) + { + ATLASSERT(nElements <= (SIZE_MAX / sizeof(T))); + return AllocateBytes(nElements * sizeof(T)); + } + + T* AllocateBytes(size_t nBytes) + { + ATLASSERT(m_p == NULL); + if(nBytes > t_nFixedBytes) + m_p = static_cast(malloc(nBytes)); + else + m_p = reinterpret_cast(m_abFixedBuffer); + + return m_p; + } + +private: + T* m_p; + BYTE m_abFixedBuffer[t_nFixedBytes]; +}; + +#pragma warning(default: 4284) + +#endif // !(_ATL_VER >= 0x0700) + + +/////////////////////////////////////////////////////////////////////////////// +// CAppModule - module class for an application + +class CAppModule : public ATL::CComModule +{ +public: + DWORD m_dwMainThreadID; + ATL::CSimpleMap* m_pMsgLoopMap; + ATL::CSimpleArray* m_pSettingChangeNotify; + +// Overrides of CComModule::Init and Term + HRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL) + { + HRESULT hRet = CComModule::Init(pObjMap, hInstance, pLibID); + if(FAILED(hRet)) + return hRet; + + m_dwMainThreadID = ::GetCurrentThreadId(); + typedef ATL::CSimpleMap _mapClass; + m_pMsgLoopMap = NULL; + ATLTRY(m_pMsgLoopMap = new _mapClass); + if(m_pMsgLoopMap == NULL) + return E_OUTOFMEMORY; + m_pSettingChangeNotify = NULL; + + return hRet; + } + + void Term() + { + TermSettingChangeNotify(); + delete m_pMsgLoopMap; + CComModule::Term(); + } + +// Message loop map methods + BOOL AddMessageLoop(CMessageLoop* pMsgLoop) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddMessageLoop.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + ATLASSERT(pMsgLoop != NULL); + ATLASSERT(m_pMsgLoopMap->Lookup(::GetCurrentThreadId()) == NULL); // not in map yet + + BOOL bRet = m_pMsgLoopMap->Add(::GetCurrentThreadId(), pMsgLoop); + + lock.Unlock(); + + return bRet; + } + + BOOL RemoveMessageLoop() + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveMessageLoop.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + BOOL bRet = m_pMsgLoopMap->Remove(::GetCurrentThreadId()); + + lock.Unlock(); + + return bRet; + } + + CMessageLoop* GetMessageLoop(DWORD dwThreadID = ::GetCurrentThreadId()) const + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::GetMessageLoop.\n")); + ATLASSERT(FALSE); + return NULL; + } + + CMessageLoop* pLoop = m_pMsgLoopMap->Lookup(dwThreadID); + + lock.Unlock(); + + return pLoop; + } + +// Setting change notify methods + // Note: Call this from the main thread for MSDI apps + BOOL InitSettingChangeNotify(DLGPROC pfnDlgProc = _SettingChangeDlgProc) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::InitSettingChangeNotify.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + if(m_pSettingChangeNotify == NULL) + { + typedef ATL::CSimpleArray _notifyClass; + ATLTRY(m_pSettingChangeNotify = new _notifyClass); + ATLASSERT(m_pSettingChangeNotify != NULL); + } + + BOOL bRet = (m_pSettingChangeNotify != NULL); + if(bRet && m_pSettingChangeNotify->GetSize() == 0) + { + // init everything + _ATL_EMPTY_DLGTEMPLATE templ; + HWND hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL, pfnDlgProc); + ATLASSERT(::IsWindow(hNtfWnd)); + if(::IsWindow(hNtfWnd)) + { +// need conditional code because types don't match in winuser.h +#ifdef _WIN64 + ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this); +#else + ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this)); +#endif + bRet = m_pSettingChangeNotify->Add(hNtfWnd); + } + else + { + bRet = FALSE; + } + } + + lock.Unlock(); + + return bRet; + } + + void TermSettingChangeNotify() + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::TermSettingChangeNotify.\n")); + ATLASSERT(FALSE); + return; + } + + if(m_pSettingChangeNotify != NULL && m_pSettingChangeNotify->GetSize() > 0) + ::DestroyWindow((*m_pSettingChangeNotify)[0]); + delete m_pSettingChangeNotify; + m_pSettingChangeNotify = NULL; + + lock.Unlock(); + } + + BOOL AddSettingChangeNotify(HWND hWnd) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddSettingChangeNotify.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + ATLASSERT(::IsWindow(hWnd)); + BOOL bRet = FALSE; + if(InitSettingChangeNotify() != FALSE) + bRet = m_pSettingChangeNotify->Add(hWnd); + + lock.Unlock(); + + return bRet; + } + + BOOL RemoveSettingChangeNotify(HWND hWnd) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveSettingChangeNotify.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + BOOL bRet = FALSE; + if(m_pSettingChangeNotify != NULL) + bRet = m_pSettingChangeNotify->Remove(hWnd); + + lock.Unlock(); + + return bRet; + } + +// Implementation - setting change notify dialog template and dialog procedure + struct _ATL_EMPTY_DLGTEMPLATE : DLGTEMPLATE + { + _ATL_EMPTY_DLGTEMPLATE() + { + memset(this, 0, sizeof(_ATL_EMPTY_DLGTEMPLATE)); + style = WS_POPUP; + } + WORD wMenu, wClass, wTitle; + }; + +#ifdef _WIN64 + static INT_PTR CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +#else + static BOOL CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +#endif + { + if(uMsg == WM_SETTINGCHANGE) + { +// need conditional code because types don't match in winuser.h +#ifdef _WIN64 + CAppModule* pModule = (CAppModule*)::GetWindowLongPtr(hWnd, GWLP_USERDATA); +#else + CAppModule* pModule = (CAppModule*)LongToPtr(::GetWindowLongPtr(hWnd, GWLP_USERDATA)); +#endif + ATLASSERT(pModule != NULL); + ATLASSERT(pModule->m_pSettingChangeNotify != NULL); + const UINT uTimeout = 1500; // ms + for(int i = 1; i < pModule->m_pSettingChangeNotify->GetSize(); i++) + { +#if !defined(_WIN32_WCE) + ::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_ABORTIFHUNG, uTimeout, NULL); +#elif(_WIN32_WCE >= 400) // CE specific + ::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_NORMAL, uTimeout, NULL); +#else // _WIN32_WCE < 400 specific + uTimeout; + ::SendMessage((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam); +#endif + } + return TRUE; + } + return FALSE; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CServerAppModule - module class for a COM server application + +class CServerAppModule : public CAppModule +{ +public: + HANDLE m_hEventShutdown; + bool m_bActivity; + DWORD m_dwTimeOut; + DWORD m_dwPause; + +// Override of CAppModule::Init + HRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL) + { + m_dwTimeOut = 5000; + m_dwPause = 1000; + return CAppModule::Init(pObjMap, hInstance, pLibID); + } + + void Term() + { + if(m_hEventShutdown != NULL && ::CloseHandle(m_hEventShutdown)) + m_hEventShutdown = NULL; + CAppModule::Term(); + } + +// COM Server methods + LONG Unlock() + { + LONG lRet = CComModule::Unlock(); + if(lRet == 0) + { + m_bActivity = true; + ::SetEvent(m_hEventShutdown); // tell monitor that we transitioned to zero + } + return lRet; + } + + void MonitorShutdown() + { + for(;;) + { + ::WaitForSingleObject(m_hEventShutdown, INFINITE); + DWORD dwWait = 0; + do + { + m_bActivity = false; + dwWait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut); + } + while(dwWait == WAIT_OBJECT_0); + // timed out + if(!m_bActivity && m_nLockCnt == 0) // if no activity let's really bail + { +#if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)) && defined(_ATL_FREE_THREADED) && !defined(_WIN32_WCE) + ::CoSuspendClassObjects(); + if(!m_bActivity && m_nLockCnt == 0) +#endif + break; + } + } + // This handle should be valid now. If it isn't, + // check if _Module.Term was called first (it shouldn't) + if(::CloseHandle(m_hEventShutdown)) + m_hEventShutdown = NULL; + ::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0); + } + + bool StartMonitor() + { + m_hEventShutdown = ::CreateEvent(NULL, false, false, NULL); + if(m_hEventShutdown == NULL) + return false; + DWORD dwThreadID = 0; +#if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE) + HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))MonitorProc, this, 0, (UINT*)&dwThreadID); +#else + HANDLE hThread = ::CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID); +#endif + bool bRet = (hThread != NULL); + if(bRet) + ::CloseHandle(hThread); + return bRet; + } + + static DWORD WINAPI MonitorProc(void* pv) + { + CServerAppModule* p = (CServerAppModule*)pv; + p->MonitorShutdown(); + return 0; + } + +#if (_ATL_VER < 0x0700) + // search for an occurence of string p2 in string p1 + static LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2) + { + while(p1 != NULL && *p1 != NULL) + { + LPCTSTR p = p2; + while(p != NULL && *p != NULL) + { + if(*p1 == *p) + return ::CharNext(p1); + p = ::CharNext(p); + } + p1 = ::CharNext(p1); + } + return NULL; + } +#endif // (_ATL_VER < 0x0700) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CString forward reference (enables CString use in atluser.h and atlgdi.h) + +#if defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING) + #define _WTL_USE_CSTRING +#endif // defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING) + +#ifdef _WTL_USE_CSTRING + class CString; // forward declaration (include atlmisc.h for the whole class) +#endif // _WTL_USE_CSTRING + +// CString namespace +#ifndef _CSTRING_NS + #ifdef __ATLSTR_H__ + #define _CSTRING_NS ATL + #else + #define _CSTRING_NS WTL + #endif +#endif // _CSTRING_NS + +// Type classes namespace +#ifndef _WTYPES_NS + #ifdef __ATLTYPES_H__ + #define _WTYPES_NS + #else + #define _WTYPES_NS WTL + #endif +#endif // _WTYPES_NS + +}; // namespace WTL + + +/////////////////////////////////////////////////////////////////////////////// +// General DLL version helpers (excluded from atlbase.h if _ATL_DLL is defined) + +#if (_ATL_VER < 0x0700) && defined(_ATL_DLL) && !defined(_WIN32_WCE) + +namespace ATL +{ + +inline HRESULT AtlGetDllVersion(HINSTANCE hInstDLL, DLLVERSIONINFO* pDllVersionInfo) +{ + ATLASSERT(pDllVersionInfo != NULL); + if(pDllVersionInfo == NULL) + return E_INVALIDARG; + + // We must get this function explicitly because some DLLs don't implement it. + DLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(hInstDLL, "DllGetVersion"); + if(pfnDllGetVersion == NULL) + return E_NOTIMPL; + + return (*pfnDllGetVersion)(pDllVersionInfo); +} + +inline HRESULT AtlGetDllVersion(LPCTSTR lpstrDllName, DLLVERSIONINFO* pDllVersionInfo) +{ + HINSTANCE hInstDLL = ::LoadLibrary(lpstrDllName); + if(hInstDLL == NULL) + return E_FAIL; + HRESULT hRet = AtlGetDllVersion(hInstDLL, pDllVersionInfo); + ::FreeLibrary(hInstDLL); + return hRet; +} + +// Common Control Versions: +// Win95/WinNT 4.0 maj=4 min=00 +// IE 3.x maj=4 min=70 +// IE 4.0 maj=4 min=71 +inline HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) +{ + ATLASSERT(pdwMajor != NULL && pdwMinor != NULL); + if(pdwMajor == NULL || pdwMinor == NULL) + return E_INVALIDARG; + + DLLVERSIONINFO dvi; + ::ZeroMemory(&dvi, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + HRESULT hRet = AtlGetDllVersion(_T("comctl32.dll"), &dvi); + + if(SUCCEEDED(hRet)) + { + *pdwMajor = dvi.dwMajorVersion; + *pdwMinor = dvi.dwMinorVersion; + } + else if(hRet == E_NOTIMPL) + { + // If DllGetVersion is not there, then the DLL is a version + // previous to the one shipped with IE 3.x + *pdwMajor = 4; + *pdwMinor = 0; + hRet = S_OK; + } + + return hRet; +} + +// Shell Versions: +// Win95/WinNT 4.0 maj=4 min=00 +// IE 3.x, IE 4.0 without Web Integrated Desktop maj=4 min=00 +// IE 4.0 with Web Integrated Desktop maj=4 min=71 +// IE 4.01 with Web Integrated Desktop maj=4 min=72 +inline HRESULT AtlGetShellVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) +{ + ATLASSERT(pdwMajor != NULL && pdwMinor != NULL); + if(pdwMajor == NULL || pdwMinor == NULL) + return E_INVALIDARG; + + DLLVERSIONINFO dvi; + ::ZeroMemory(&dvi, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + HRESULT hRet = AtlGetDllVersion(_T("shell32.dll"), &dvi); + + if(SUCCEEDED(hRet)) + { + *pdwMajor = dvi.dwMajorVersion; + *pdwMinor = dvi.dwMinorVersion; + } + else if(hRet == E_NOTIMPL) + { + // If DllGetVersion is not there, then the DLL is a version + // previous to the one shipped with IE 4.x + *pdwMajor = 4; + *pdwMinor = 0; + hRet = S_OK; + } + + return hRet; +} + +}; // namespace ATL + +#endif // (_ATL_VER < 0x0700) && defined(_ATL_DLL) && !defined(_WIN32_WCE) + + +// These are always included +#include "atlwinx.h" +#include "atluser.h" +#include "atlgdi.h" + +#ifndef _WTL_NO_AUTOMATIC_NAMESPACE +using namespace WTL; +#endif // !_WTL_NO_AUTOMATIC_NAMESPACE + +#endif // __ATLAPP_H__ diff --git a/wtl/wtl/include/atlcrack.h b/wtl/wtl/include/atlcrack.h new file mode 100644 index 00000000..f92b35ad --- /dev/null +++ b/wtl/wtl/include/atlcrack.h @@ -0,0 +1,2380 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLCRACK_H__ +#define __ATLCRACK_H__ + +#pragma once + + +/////////////////////////////////////////////////////////////////////////////// +// Message map macro for cracked handlers + +// Note about message maps with cracked handlers: +// For ATL 3.0, a message map using cracked handlers MUST use BEGIN_MSG_MAP_EX. +// For ATL 7.0 or higher, you can use BEGIN_MSG_MAP for CWindowImpl/CDialogImpl derived classes, +// but must use BEGIN_MSG_MAP_EX for classes that don't derive from CWindowImpl/CDialogImpl. + +#define BEGIN_MSG_MAP_EX(theClass) \ +public: \ + BOOL m_bMsgHandled; \ + /* "handled" management for cracked handlers */ \ + BOOL IsMsgHandled() const \ + { \ + return m_bMsgHandled; \ + } \ + void SetMsgHandled(BOOL bHandled) \ + { \ + m_bMsgHandled = bHandled; \ + } \ + BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \ + { \ + BOOL bOldMsgHandled = m_bMsgHandled; \ + BOOL bRet = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \ + m_bMsgHandled = bOldMsgHandled; \ + return bRet; \ + } \ + BOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID) \ + { \ + BOOL bHandled = TRUE; \ + hWnd; \ + uMsg; \ + wParam; \ + lParam; \ + lResult; \ + bHandled; \ + switch(dwMsgMapID) \ + { \ + case 0: + + +/////////////////////////////////////////////////////////////////////////////// +// Standard Windows message macros + +// int OnCreate(LPCREATESTRUCT lpCreateStruct) +#define MSG_WM_CREATE(func) \ + if (uMsg == WM_CREATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam) +#define MSG_WM_INITDIALOG(func) \ + if (uMsg == WM_INITDIALOG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnCopyData(CWindow wnd, PCOPYDATASTRUCT pCopyDataStruct) +#define MSG_WM_COPYDATA(func) \ + if (uMsg == WM_COPYDATA) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, (PCOPYDATASTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDestroy() +#define MSG_WM_DESTROY(func) \ + if (uMsg == WM_DESTROY) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMove(CPoint ptPos) +#define MSG_WM_MOVE(func) \ + if (uMsg == WM_MOVE) \ + { \ + SetMsgHandled(TRUE); \ + func(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSize(UINT nType, CSize size) +#define MSG_WM_SIZE(func) \ + if (uMsg == WM_SIZE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnActivate(UINT nState, BOOL bMinimized, CWindow wndOther) +#define MSG_WM_ACTIVATE(func) \ + if (uMsg == WM_ACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)LOWORD(wParam), (BOOL)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSetFocus(CWindow wndOld) +#define MSG_WM_SETFOCUS(func) \ + if (uMsg == WM_SETFOCUS) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnKillFocus(CWindow wndFocus) +#define MSG_WM_KILLFOCUS(func) \ + if (uMsg == WM_KILLFOCUS) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEnable(BOOL bEnable) +#define MSG_WM_ENABLE(func) \ + if (uMsg == WM_ENABLE) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaint(CDCHandle dc) +#define MSG_WM_PAINT(func) \ + if (uMsg == WM_PAINT) \ + { \ + SetMsgHandled(TRUE); \ + func((HDC)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnClose() +#define MSG_WM_CLOSE(func) \ + if (uMsg == WM_CLOSE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnQueryEndSession(UINT nSource, UINT uLogOff) +#define MSG_WM_QUERYENDSESSION(func) \ + if (uMsg == WM_QUERYENDSESSION) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (UINT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnQueryOpen() +#define MSG_WM_QUERYOPEN(func) \ + if (uMsg == WM_QUERYOPEN) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnEraseBkgnd(CDCHandle dc) +#define MSG_WM_ERASEBKGND(func) \ + if (uMsg == WM_ERASEBKGND) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysColorChange() +#define MSG_WM_SYSCOLORCHANGE(func) \ + if (uMsg == WM_SYSCOLORCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEndSession(BOOL bEnding, UINT uLogOff) +#define MSG_WM_ENDSESSION(func) \ + if (uMsg == WM_ENDSESSION) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam, (UINT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnShowWindow(BOOL bShow, UINT nStatus) +#define MSG_WM_SHOWWINDOW(func) \ + if (uMsg == WM_SHOWWINDOW) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam, (int)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorEdit(CDCHandle dc, CEdit edit) +#define MSG_WM_CTLCOLOREDIT(func) \ + if (uMsg == WM_CTLCOLOREDIT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorListBox(CDCHandle dc, CListBox listBox) +#define MSG_WM_CTLCOLORLISTBOX(func) \ + if (uMsg == WM_CTLCOLORLISTBOX) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorBtn(CDCHandle dc, CButton button) +#define MSG_WM_CTLCOLORBTN(func) \ + if (uMsg == WM_CTLCOLORBTN) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorDlg(CDCHandle dc, CWindow wnd) +#define MSG_WM_CTLCOLORDLG(func) \ + if (uMsg == WM_CTLCOLORDLG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar) +#define MSG_WM_CTLCOLORSCROLLBAR(func) \ + if (uMsg == WM_CTLCOLORSCROLLBAR) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic) +#define MSG_WM_CTLCOLORSTATIC(func) \ + if (uMsg == WM_CTLCOLORSTATIC) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSettingChange(UINT uFlags, LPCTSTR lpszSection) +#define MSG_WM_SETTINGCHANGE(func) \ + if (uMsg == WM_SETTINGCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPCTSTR)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDevModeChange(LPCTSTR lpDeviceName) +#define MSG_WM_DEVMODECHANGE(func) \ + if (uMsg == WM_DEVMODECHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func((LPCTSTR)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnActivateApp(BOOL bActive, DWORD dwThreadID) +#define MSG_WM_ACTIVATEAPP(func) \ + if (uMsg == WM_ACTIVATEAPP) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam, (DWORD)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnFontChange() +#define MSG_WM_FONTCHANGE(func) \ + if (uMsg == WM_FONTCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnTimeChange() +#define MSG_WM_TIMECHANGE(func) \ + if (uMsg == WM_TIMECHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCancelMode() +#define MSG_WM_CANCELMODE(func) \ + if (uMsg == WM_CANCELMODE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message) +#define MSG_WM_SETCURSOR(func) \ + if (uMsg == WM_SETCURSOR) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message) +#define MSG_WM_MOUSEACTIVATE(func) \ + if (uMsg == WM_MOUSEACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnChildActivate() +#define MSG_WM_CHILDACTIVATE(func) \ + if (uMsg == WM_CHILDACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnGetMinMaxInfo(LPMINMAXINFO lpMMI) +#define MSG_WM_GETMINMAXINFO(func) \ + if (uMsg == WM_GETMINMAXINFO) \ + { \ + SetMsgHandled(TRUE); \ + func((LPMINMAXINFO)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnIconEraseBkgnd(CDCHandle dc) +#define MSG_WM_ICONERASEBKGND(func) \ + if (uMsg == WM_ICONERASEBKGND) \ + { \ + SetMsgHandled(TRUE); \ + func((HDC)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSpoolerStatus(UINT nStatus, UINT nJobs) +#define MSG_WM_SPOOLERSTATUS(func) \ + if (uMsg == WM_SPOOLERSTATUS) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (UINT)LOWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +#define MSG_WM_DRAWITEM(func) \ + if (uMsg == WM_DRAWITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) +#define MSG_WM_MEASUREITEM(func) \ + if (uMsg == WM_MEASUREITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct) +#define MSG_WM_DELETEITEM(func) \ + if (uMsg == WM_DELETEITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +//int OnCharToItem(UINT nChar, UINT nIndex, CListBox listBox) +#define MSG_WM_CHARTOITEM(func) \ + if (uMsg == WM_CHARTOITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox) +#define MSG_WM_VKEYTOITEM(func) \ + if (uMsg == WM_VKEYTOITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HCURSOR OnQueryDragIcon() +#define MSG_WM_QUERYDRAGICON(func) \ + if (uMsg == WM_QUERYDRAGICON) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct) +#define MSG_WM_COMPAREITEM(func) \ + if (uMsg == WM_COMPAREITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCompacting(UINT nCpuTime) +#define MSG_WM_COMPACTING(func) \ + if (uMsg == WM_COMPACTING) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct) +#define MSG_WM_NCCREATE(func) \ + if (uMsg == WM_NCCREATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcDestroy() +#define MSG_WM_NCDESTROY(func) \ + if (uMsg == WM_NCDESTROY) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNcCalcSize(BOOL bCalcValidRects, LPARAM lParam) +#define MSG_WM_NCCALCSIZE(func) \ + if (uMsg == WM_NCCALCSIZE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((BOOL)wParam, lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// UINT OnNcHitTest(CPoint point) +#define MSG_WM_NCHITTEST(func) \ + if (uMsg == WM_NCHITTEST) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcPaint(CRgn rgn) +#define MSG_WM_NCPAINT(func) \ + if (uMsg == WM_NCPAINT) \ + { \ + SetMsgHandled(TRUE); \ + func((HRGN)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnNcActivate(BOOL bActive) +#define MSG_WM_NCACTIVATE(func) \ + if (uMsg == WM_NCACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((BOOL)wParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// UINT OnGetDlgCode(LPMSG lpMsg) +#define MSG_WM_GETDLGCODE(func) \ + if (uMsg == WM_GETDLGCODE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPMSG)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcMouseMove(UINT nHitTest, CPoint point) +#define MSG_WM_NCMOUSEMOVE(func) \ + if (uMsg == WM_NCMOUSEMOVE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcLButtonDown(UINT nHitTest, CPoint point) +#define MSG_WM_NCLBUTTONDOWN(func) \ + if (uMsg == WM_NCLBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcLButtonUp(UINT nHitTest, CPoint point) +#define MSG_WM_NCLBUTTONUP(func) \ + if (uMsg == WM_NCLBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcLButtonDblClk(UINT nHitTest, CPoint point) +#define MSG_WM_NCLBUTTONDBLCLK(func) \ + if (uMsg == WM_NCLBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcRButtonDown(UINT nHitTest, CPoint point) +#define MSG_WM_NCRBUTTONDOWN(func) \ + if (uMsg == WM_NCRBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcRButtonUp(UINT nHitTest, CPoint point) +#define MSG_WM_NCRBUTTONUP(func) \ + if (uMsg == WM_NCRBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcRButtonDblClk(UINT nHitTest, CPoint point) +#define MSG_WM_NCRBUTTONDBLCLK(func) \ + if (uMsg == WM_NCRBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcMButtonDown(UINT nHitTest, CPoint point) +#define MSG_WM_NCMBUTTONDOWN(func) \ + if (uMsg == WM_NCMBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcMButtonUp(UINT nHitTest, CPoint point) +#define MSG_WM_NCMBUTTONUP(func) \ + if (uMsg == WM_NCMBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNcMButtonDblClk(UINT nHitTest, CPoint point) +#define MSG_WM_NCMBUTTONDBLCLK(func) \ + if (uMsg == WM_NCMBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_KEYDOWN(func) \ + if (uMsg == WM_KEYDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_KEYUP(func) \ + if (uMsg == WM_KEYUP) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_CHAR(func) \ + if (uMsg == WM_CHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_DEADCHAR(func) \ + if (uMsg == WM_DEADCHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_SYSKEYDOWN(func) \ + if (uMsg == WM_SYSKEYDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_SYSKEYUP(func) \ + if (uMsg == WM_SYSKEYUP) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_SYSCHAR(func) \ + if (uMsg == WM_SYSCHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_SYSDEADCHAR(func) \ + if (uMsg == WM_SYSDEADCHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSysCommand(UINT nID, LPARAM lParam) +#define MSG_WM_SYSCOMMAND(func) \ + if (uMsg == WM_SYSCOMMAND) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnTCard(UINT idAction, DWORD dwActionData) +#define MSG_WM_TCARD(func) \ + if (uMsg == WM_TCARD) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (DWORD)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnTimer(UINT_PTR nIDEvent) +#define MSG_WM_TIMER(func) \ + if (uMsg == WM_TIMER) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT_PTR)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) +#define MSG_WM_HSCROLL(func) \ + if (uMsg == WM_HSCROLL) \ + { \ + SetMsgHandled(TRUE); \ + func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) +#define MSG_WM_VSCROLL(func) \ + if (uMsg == WM_VSCROLL) \ + { \ + SetMsgHandled(TRUE); \ + func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnInitMenu(CMenu menu) +#define MSG_WM_INITMENU(func) \ + if (uMsg == WM_INITMENU) \ + { \ + SetMsgHandled(TRUE); \ + func((HMENU)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnInitMenuPopup(CMenu menuPopup, UINT nIndex, BOOL bSysMenu) +#define MSG_WM_INITMENUPOPUP(func) \ + if (uMsg == WM_INITMENUPOPUP) \ + { \ + SetMsgHandled(TRUE); \ + func((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMenuSelect(UINT nItemID, UINT nFlags, CMenu menu) +#define MSG_WM_MENUSELECT(func) \ + if (uMsg == WM_MENUSELECT) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenu menu) +#define MSG_WM_MENUCHAR(func) \ + if (uMsg == WM_MENUCHAR) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((TCHAR)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotify(int idCtrl, LPNMHDR pnmh) +#define MSG_WM_NOTIFY(func) \ + if (uMsg == WM_NOTIFY) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((int)wParam, (LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEnterIdle(UINT nWhy, CWindow wndWho) +#define MSG_WM_ENTERIDLE(func) \ + if (uMsg == WM_ENTERIDLE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMouseMove(UINT nFlags, CPoint point) +#define MSG_WM_MOUSEMOVE(func) \ + if (uMsg == WM_MOUSEMOVE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +#define MSG_WM_MOUSEWHEEL(func) \ + if (uMsg == WM_MOUSEWHEEL) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (short)HIWORD(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnLButtonDown(UINT nFlags, CPoint point) +#define MSG_WM_LBUTTONDOWN(func) \ + if (uMsg == WM_LBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnLButtonUp(UINT nFlags, CPoint point) +#define MSG_WM_LBUTTONUP(func) \ + if (uMsg == WM_LBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnLButtonDblClk(UINT nFlags, CPoint point) +#define MSG_WM_LBUTTONDBLCLK(func) \ + if (uMsg == WM_LBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRButtonDown(UINT nFlags, CPoint point) +#define MSG_WM_RBUTTONDOWN(func) \ + if (uMsg == WM_RBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRButtonUp(UINT nFlags, CPoint point) +#define MSG_WM_RBUTTONUP(func) \ + if (uMsg == WM_RBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRButtonDblClk(UINT nFlags, CPoint point) +#define MSG_WM_RBUTTONDBLCLK(func) \ + if (uMsg == WM_RBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMButtonDown(UINT nFlags, CPoint point) +#define MSG_WM_MBUTTONDOWN(func) \ + if (uMsg == WM_MBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMButtonUp(UINT nFlags, CPoint point) +#define MSG_WM_MBUTTONUP(func) \ + if (uMsg == WM_MBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMButtonDblClk(UINT nFlags, CPoint point) +#define MSG_WM_MBUTTONDBLCLK(func) \ + if (uMsg == WM_MBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnParentNotify(UINT message, UINT nChildID, LPARAM lParam) +#define MSG_WM_PARENTNOTIFY(func) \ + if (uMsg == WM_PARENTNOTIFY) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMDIActivate(CWindow wndActivate, CWindow wndDeactivate) +#define MSG_WM_MDIACTIVATE(func) \ + if (uMsg == WM_MDIACTIVATE) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRenderFormat(UINT nFormat) +#define MSG_WM_RENDERFORMAT(func) \ + if (uMsg == WM_RENDERFORMAT) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRenderAllFormats() +#define MSG_WM_RENDERALLFORMATS(func) \ + if (uMsg == WM_RENDERALLFORMATS) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDestroyClipboard() +#define MSG_WM_DESTROYCLIPBOARD(func) \ + if (uMsg == WM_DESTROYCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDrawClipboard() +#define MSG_WM_DRAWCLIPBOARD(func) \ + if (uMsg == WM_DRAWCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaintClipboard(CWindow wndViewer, const LPPAINTSTRUCT lpPaintStruct) +#define MSG_WM_PAINTCLIPBOARD(func) \ + if (uMsg == WM_PAINTCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (const LPPAINTSTRUCT)::GlobalLock((HGLOBAL)lParam)); \ + ::GlobalUnlock((HGLOBAL)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnVScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos) +#define MSG_WM_VSCROLLCLIPBOARD(func) \ + if (uMsg == WM_VSCROLLCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnContextMenu(CWindow wnd, CPoint point) +#define MSG_WM_CONTEXTMENU(func) \ + if (uMsg == WM_CONTEXTMENU) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSizeClipboard(CWindow wndViewer, const LPRECT lpRect) +#define MSG_WM_SIZECLIPBOARD(func) \ + if (uMsg == WM_SIZECLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (const LPRECT)::GlobalLock((HGLOBAL)lParam)); \ + ::GlobalUnlock((HGLOBAL)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnAskCbFormatName(UINT nMaxCount, LPTSTR lpszString) +#define MSG_WM_ASKCBFORMATNAME(func) \ + if (uMsg == WM_ASKCBFORMATNAME) \ + { \ + SetMsgHandled(TRUE); \ + func((DWORD)wParam, (LPTSTR)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnChangeCbChain(CWindow wndRemove, CWindow wndAfter) +#define MSG_WM_CHANGECBCHAIN(func) \ + if (uMsg == WM_CHANGECBCHAIN) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnHScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos) +#define MSG_WM_HSCROLLCLIPBOARD(func) \ + if (uMsg == WM_HSCROLLCLIPBOARD) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnQueryNewPalette() +#define MSG_WM_QUERYNEWPALETTE(func) \ + if (uMsg == WM_QUERYNEWPALETTE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaletteChanged(CWindow wndFocus) +#define MSG_WM_PALETTECHANGED(func) \ + if (uMsg == WM_PALETTECHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaletteIsChanging(CWindow wndPalChg) +#define MSG_WM_PALETTEISCHANGING(func) \ + if (uMsg == WM_PALETTEISCHANGING) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDropFiles(HDROP hDropInfo) +#define MSG_WM_DROPFILES(func) \ + if (uMsg == WM_DROPFILES) \ + { \ + SetMsgHandled(TRUE); \ + func((HDROP)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnWindowPosChanging(LPWINDOWPOS lpWndPos) +#define MSG_WM_WINDOWPOSCHANGING(func) \ + if (uMsg == WM_WINDOWPOSCHANGING) \ + { \ + SetMsgHandled(TRUE); \ + func((LPWINDOWPOS)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnWindowPosChanged(LPWINDOWPOS lpWndPos) +#define MSG_WM_WINDOWPOSCHANGED(func) \ + if (uMsg == WM_WINDOWPOSCHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func((LPWINDOWPOS)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnExitMenuLoop(BOOL fIsTrackPopupMenu) +#define MSG_WM_EXITMENULOOP(func) \ + if (uMsg == WM_EXITMENULOOP) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEnterMenuLoop(BOOL fIsTrackPopupMenu) +#define MSG_WM_ENTERMENULOOP(func) \ + if (uMsg == WM_ENTERMENULOOP) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct) +#define MSG_WM_STYLECHANGED(func) \ + if (uMsg == WM_STYLECHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPSTYLESTRUCT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnStyleChanging(int nStyleType, LPSTYLESTRUCT lpStyleStruct) +#define MSG_WM_STYLECHANGING(func) \ + if (uMsg == WM_STYLECHANGING) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPSTYLESTRUCT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSizing(UINT fwSide, LPRECT pRect) +#define MSG_WM_SIZING(func) \ + if (uMsg == WM_SIZING) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPRECT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMoving(UINT fwSide, LPRECT pRect) +#define MSG_WM_MOVING(func) \ + if (uMsg == WM_MOVING) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPRECT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCaptureChanged(CWindow wnd) +#define MSG_WM_CAPTURECHANGED(func) \ + if (uMsg == WM_CAPTURECHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func((HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnDeviceChange(UINT nEventType, DWORD dwData) +#define MSG_WM_DEVICECHANGE(func) \ + if (uMsg == WM_DEVICECHANGE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (DWORD)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) +#define MSG_WM_COMMAND(func) \ + if (uMsg == WM_COMMAND) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDisplayChange(UINT uBitsPerPixel, CSize sizeScreen) +#define MSG_WM_DISPLAYCHANGE(func) \ + if (uMsg == WM_DISPLAYCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnEnterSizeMove() +#define MSG_WM_ENTERSIZEMOVE(func) \ + if (uMsg == WM_ENTERSIZEMOVE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnExitSizeMove() +#define MSG_WM_EXITSIZEMOVE(func) \ + if (uMsg == WM_EXITSIZEMOVE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HFONT OnGetFont() +#define MSG_WM_GETFONT(func) \ + if (uMsg == WM_GETFONT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnGetHotKey() +#define MSG_WM_GETHOTKEY(func) \ + if (uMsg == WM_GETHOTKEY) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HICON OnGetIcon() +#define MSG_WM_GETICON(func) \ + if (uMsg == WM_GETICON) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnGetText(int cchTextMax, LPTSTR lpszText) +#define MSG_WM_GETTEXT(func) \ + if (uMsg == WM_GETTEXT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((int)wParam, (LPTSTR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnGetTextLength() +#define MSG_WM_GETTEXTLENGTH(func) \ + if (uMsg == WM_GETTEXTLENGTH) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnHelp(LPHELPINFO lpHelpInfo) +#define MSG_WM_HELP(func) \ + if (uMsg == WM_HELP) \ + { \ + SetMsgHandled(TRUE); \ + func((LPHELPINFO)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnHotKey(int nHotKeyID, UINT uModifiers, UINT uVirtKey) +#define MSG_WM_HOTKEY(func) \ + if (uMsg == WM_HOTKEY) \ + { \ + SetMsgHandled(TRUE); \ + func((int)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnInputLangChange(DWORD dwCharSet, HKL hKbdLayout) +#define MSG_WM_INPUTLANGCHANGE(func) \ + if (uMsg == WM_INPUTLANGCHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func((DWORD)wParam, (HKL)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnInputLangChangeRequest(BOOL bSysCharSet, HKL hKbdLayout) +#define MSG_WM_INPUTLANGCHANGEREQUEST(func) \ + if (uMsg == WM_INPUTLANGCHANGEREQUEST) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam, (HKL)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNextDlgCtl(BOOL bHandle, WPARAM wCtlFocus) +#define MSG_WM_NEXTDLGCTL(func) \ + if (uMsg == WM_NEXTDLGCTL) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)LOWORD(lParam), wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNextMenu(int nVirtKey, LPMDINEXTMENU lpMdiNextMenu) +#define MSG_WM_NEXTMENU(func) \ + if (uMsg == WM_NEXTMENU) \ + { \ + SetMsgHandled(TRUE); \ + func((int)wParam, (LPMDINEXTMENU)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnNotifyFormat(CWindow wndFrom, int nCommand) +#define MSG_WM_NOTIFYFORMAT(func) \ + if (uMsg == WM_NOTIFYFORMAT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, (int)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// BOOL OnPowerBroadcast(DWORD dwPowerEvent, DWORD dwData) +#define MSG_WM_POWERBROADCAST(func) \ + if (uMsg == WM_POWERBROADCAST) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((DWORD)wParam, (DWORD)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPrint(CDCHandle dc, UINT uFlags) +#define MSG_WM_PRINT(func) \ + if (uMsg == WM_PRINT) \ + { \ + SetMsgHandled(TRUE); \ + func((HDC)wParam, (UINT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPrintClient(CDCHandle dc, UINT uFlags) +#define MSG_WM_PRINTCLIENT(func) \ + if (uMsg == WM_PRINTCLIENT) \ + { \ + SetMsgHandled(TRUE); \ + func((HDC)wParam, (UINT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnRasDialEvent(RASCONNSTATE rasconnstate, DWORD dwError) +#define MSG_WM_RASDIALEVENT(func) \ + if (uMsg == WM_RASDIALEVENT) \ + { \ + SetMsgHandled(TRUE); \ + func((RASCONNSTATE)wParam, (DWORD)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSetFont(CFont font, BOOL bRedraw) +#define MSG_WM_SETFONT(func) \ + if (uMsg == WM_SETFONT) \ + { \ + SetMsgHandled(TRUE); \ + func((HFONT)wParam, (BOOL)LOWORD(lParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnSetHotKey(int nVirtKey, UINT uFlags) +#define MSG_WM_SETHOTKEY(func) \ + if (uMsg == WM_SETHOTKEY) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((int)LOBYTE(LOWORD(wParam)), (UINT)HIBYTE(LOWORD(wParam))); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HICON OnSetIcon(UINT uType, HICON hIcon) +#define MSG_WM_SETICON(func) \ + if (uMsg == WM_SETICON) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (HICON)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnSetRedraw(BOOL bRedraw) +#define MSG_WM_SETREDRAW(func) \ + if (uMsg == WM_SETREDRAW) \ + { \ + SetMsgHandled(TRUE); \ + func((BOOL)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnSetText(LPCTSTR lpstrText) +#define MSG_WM_SETTEXT(func) \ + if (uMsg == WM_SETTEXT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPCTSTR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUserChanged() +#define MSG_WM_USERCHANGED(func) \ + if (uMsg == WM_USERCHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// New NT4 & NT5 messages + +#if(_WIN32_WINNT >= 0x0400) + +// void OnMouseHover(WPARAM wParam, CPoint ptPos) +#define MSG_WM_MOUSEHOVER(func) \ + if (uMsg == WM_MOUSEHOVER) \ + { \ + SetMsgHandled(TRUE); \ + func(wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMouseLeave() +#define MSG_WM_MOUSELEAVE(func) \ + if (uMsg == WM_MOUSELEAVE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif /* _WIN32_WINNT >= 0x0400 */ + +#if(WINVER >= 0x0500) + +// void OnMenuRButtonUp(WPARAM wParam, CMenu menu) +#define MSG_WM_MENURBUTTONUP(func) \ + if (uMsg == WM_MENURBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func(wParam, (HMENU)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnMenuDrag(WPARAM wParam, CMenu menu) +#define MSG_WM_MENUDRAG(func) \ + if (uMsg == WM_MENUDRAG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(wParam, (HMENU)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnMenuGetObject(PMENUGETOBJECTINFO info) +#define MSG_WM_MENUGETOBJECT(func) \ + if (uMsg == WM_MENUGETOBJECT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((PMENUGETOBJECTINFO)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUnInitMenuPopup(UINT nID, CMenu menu) +#define MSG_WM_UNINITMENUPOPUP(func) \ + if (uMsg == WM_UNINITMENUPOPUP) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(lParam), (HMENU)wParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnMenuCommand(WPARAM nIndex, CMenu menu) +#define MSG_WM_MENUCOMMAND(func) \ + if (uMsg == WM_MENUCOMMAND) \ + { \ + SetMsgHandled(TRUE); \ + func(wParam, (HMENU)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif /* WINVER >= 0x0500 */ + +#if(_WIN32_WINNT >= 0x0500) + +// BOOL OnAppCommand(CWindow wndFocus, short cmd, WORD uDevice, int dwKeys) +#define MSG_WM_APPCOMMAND(func) \ + if (uMsg == WM_APPCOMMAND) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HWND)wParam, GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam)); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNCXButtonDown(int fwButton, short nHittest, CPoint ptPos) +#define MSG_WM_NCXBUTTONDOWN(func) \ + if (uMsg == WM_NCXBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNCXButtonUp(int fwButton, short nHittest, CPoint ptPos) +#define MSG_WM_NCXBUTTONUP(func) \ + if (uMsg == WM_NCXBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnNCXButtonDblClk(int fwButton, short nHittest, CPoint ptPos) +#define MSG_WM_NCXBUTTONDBLCLK(func) \ + if (uMsg == WM_NCXBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnXButtonDown(int fwButton, int dwKeys, CPoint ptPos) +#define MSG_WM_XBUTTONDOWN(func) \ + if (uMsg == WM_XBUTTONDOWN) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnXButtonUp(int fwButton, int dwKeys, CPoint ptPos) +#define MSG_WM_XBUTTONUP(func) \ + if (uMsg == WM_XBUTTONUP) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnXButtonDblClk(int fwButton, int dwKeys, CPoint ptPos) +#define MSG_WM_XBUTTONDBLCLK(func) \ + if (uMsg == WM_XBUTTONDBLCLK) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnChangeUIState(WORD nAction, WORD nState) +#define MSG_WM_CHANGEUISTATE(func) \ + if (uMsg == WM_CHANGEUISTATE) \ + { \ + SetMsgHandled(TRUE); \ + func(LOWORD(wParam), HIWORD(wParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUpdateUIState(WORD nAction, WORD nState) +#define MSG_WM_UPDATEUISTATE(func) \ + if (uMsg == WM_UPDATEUISTATE) \ + { \ + SetMsgHandled(TRUE); \ + func(LOWORD(wParam), HIWORD(wParam)); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnQueryUIState() +#define MSG_WM_QUERYUISTATE(func) \ + if (uMsg == WM_QUERYUISTATE) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif // (_WIN32_WINNT >= 0x0500) + +#if(_WIN32_WINNT >= 0x0501) + +// void OnInput(WPARAM RawInputCode, HRAWINPUT hRawInput) +#define MSG_WM_INPUT(func) \ + if (uMsg == WM_INPUT) \ + { \ + SetMsgHandled(TRUE); \ + func(GET_RAWINPUT_CODE_WPARAM(wParam), (HRAWINPUT)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUniChar(TCHAR nChar, UINT nRepCnt, UINT nFlags) +#define MSG_WM_UNICHAR(func) \ + if (uMsg == WM_UNICHAR) \ + { \ + SetMsgHandled(TRUE); \ + func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ + if(IsMsgHandled()) \ + { \ + lResult = (wParam == UNICODE_NOCHAR) ? TRUE : FALSE; \ + return TRUE; \ + } \ + } + +// void OnWTSSessionChange(WPARAM nStatusCode, PWTSSESSION_NOTIFICATION nSessionID) +#define MSG_WM_WTSSESSION_CHANGE(func) \ + if (uMsg == WM_WTSSESSION_CHANGE) \ + { \ + SetMsgHandled(TRUE); \ + func(wParam, (PWTSSESSION_NOTIFICATION)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// OnThemeChanged() +#define MSG_WM_THEMECHANGED(func) \ + if (uMsg == WM_THEMECHANGED) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif /* _WIN32_WINNT >= 0x0501 */ + +/////////////////////////////////////////////////////////////////////////////// +// ATL defined messages + +// BOOL OnForwardMsg(LPMSG Msg, DWORD nUserData) +#define MSG_WM_FORWARDMSG(func) \ + if (uMsg == WM_FORWARDMSG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((LPMSG)lParam, (DWORD)wParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Dialog specific messages + +// LRESULT OnDMGetDefID() +#define MSG_DM_GETDEFID(func) \ + if (uMsg == DM_GETDEFID) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDMSetDefID(UINT DefID) +#define MSG_DM_SETDEFID(func) \ + if (uMsg == DM_SETDEFID) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnDMReposition() +#define MSG_DM_REPOSITION(func) \ + if (uMsg == DM_REPOSITION) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Reflected messages + +// void OnReflectedCommand(UINT uNotifyCode, int nID, CWindow wndCtl) +#define MSG_OCM_COMMAND(func) \ + if (uMsg == OCM_COMMAND) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotify(int idCtrl, LPNMHDR pnmh) +#define MSG_OCM_NOTIFY(func) \ + if (uMsg == OCM_NOTIFY) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((int)wParam, (LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedParentNotify(UINT message, UINT nChildID, LPARAM lParam) +#define MSG_OCM_PARENTNOTIFY(func) \ + if (uMsg == OCM_PARENTNOTIFY) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +#define MSG_OCM_DRAWITEM(func) \ + if (uMsg == OCM_DRAWITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) +#define MSG_OCM_MEASUREITEM(func) \ + if (uMsg == OCM_MEASUREITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnReflectedCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct) +#define MSG_OCM_COMPAREITEM(func) \ + if (uMsg == OCM_COMPAREITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct) +#define MSG_OCM_DELETEITEM(func) \ + if (uMsg == OCM_DELETEITEM) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \ + lResult = TRUE; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// int OnReflectedVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox) +#define MSG_OCM_VKEYTOITEM(func) \ + if (uMsg == OCM_VKEYTOITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +//int OnReflectedCharToItem(UINT nChar, UINT nIndex, CListBox listBox) +#define MSG_OCM_CHARTOITEM(func) \ + if (uMsg == OCM_CHARTOITEM) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) +#define MSG_OCM_HSCROLL(func) \ + if (uMsg == OCM_HSCROLL) \ + { \ + SetMsgHandled(TRUE); \ + func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) +#define MSG_OCM_VSCROLL(func) \ + if (uMsg == OCM_VSCROLL) \ + { \ + SetMsgHandled(TRUE); \ + func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorEdit(CDCHandle dc, CEdit edit) +#define MSG_OCM_CTLCOLOREDIT(func) \ + if (uMsg == OCM_CTLCOLOREDIT) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorListBox(CDCHandle dc, CListBox listBox) +#define MSG_OCM_CTLCOLORLISTBOX(func) \ + if (uMsg == OCM_CTLCOLORLISTBOX) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorBtn(CDCHandle dc, CButton button) +#define MSG_OCM_CTLCOLORBTN(func) \ + if (uMsg == OCM_CTLCOLORBTN) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorDlg(CDCHandle dc, CWindow wnd) +#define MSG_OCM_CTLCOLORDLG(func) \ + if (uMsg == OCM_CTLCOLORDLG) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar) +#define MSG_OCM_CTLCOLORSCROLLBAR(func) \ + if (uMsg == OCM_CTLCOLORSCROLLBAR) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// HBRUSH OnReflectedCtlColorStatic(CDCHandle dc, CStatic wndStatic) +#define MSG_OCM_CTLCOLORSTATIC(func) \ + if (uMsg == OCM_CTLCOLORSTATIC) \ + { \ + SetMsgHandled(TRUE); \ + lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Edit specific messages + +// void OnClear() +#define MSG_WM_CLEAR(func) \ + if (uMsg == WM_CLEAR) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCopy() +#define MSG_WM_COPY(func) \ + if (uMsg == WM_COPY) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCut() +#define MSG_WM_CUT(func) \ + if (uMsg == WM_CUT) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnPaste() +#define MSG_WM_PASTE(func) \ + if (uMsg == WM_PASTE) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnUndo() +#define MSG_WM_UNDO(func) \ + if (uMsg == WM_UNDO) \ + { \ + SetMsgHandled(TRUE); \ + func(); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Generic message handlers + +// LRESULT OnMessageHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam) +#define MESSAGE_HANDLER_EX(msg, func) \ + if(uMsg == msg) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(uMsg, wParam, lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnMessageRangeHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam) +#define MESSAGE_RANGE_HANDLER_EX(msgFirst, msgLast, func) \ + if(uMsg >= msgFirst && uMsg <= msgLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func(uMsg, wParam, lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// Commands and notifications + +// void OnCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_HANDLER_EX(id, code, func) \ + if (uMsg == WM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_ID_HANDLER_EX(id, func) \ + if (uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_CODE_HANDLER_EX(code, func) \ + if (uMsg == WM_COMMAND && code == HIWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyHandlerEX(LPNMHDR pnmh) +#define NOTIFY_HANDLER_EX(id, cd, func) \ + if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyIDHandlerEX(LPNMHDR pnmh) +#define NOTIFY_ID_HANDLER_EX(id, func) \ + if (uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyCodeHandlerEX(LPNMHDR pnmh) +#define NOTIFY_CODE_HANDLER_EX(cd, func) \ + if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \ + if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \ + if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyRangeHandlerEX(LPNMHDR pnmh) +#define NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \ + if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnNotifyRangeCodeHandlerEX(LPNMHDR pnmh) +#define NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \ + if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_HANDLER_EX(id, code, func) \ + if (uMsg == OCM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_ID_HANDLER_EX(id, func) \ + if (uMsg == OCM_COMMAND && id == LOWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_CODE_HANDLER_EX(code, func) \ + if (uMsg == OCM_COMMAND && code == HIWORD(wParam)) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_HANDLER_EX(id, cd, func) \ + if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyIDHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_ID_HANDLER_EX(id, func) \ + if (uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyCodeHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_CODE_HANDLER_EX(cd, func) \ + if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \ + if(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// void OnReflectedCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) +#define REFLECTED_COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \ + if(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ + lResult = 0; \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyRangeHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \ + if(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +// LRESULT OnReflectedNotifyRangeCodeHandlerEX(LPNMHDR pnmh) +#define REFLECTED_NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \ + if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + SetMsgHandled(TRUE); \ + lResult = func((LPNMHDR)lParam); \ + if(IsMsgHandled()) \ + return TRUE; \ + } + +#endif // __ATLCRACK_H__ diff --git a/wtl/wtl/include/atlctrls.h b/wtl/wtl/include/atlctrls.h new file mode 100644 index 00000000..575c9c54 --- /dev/null +++ b/wtl/wtl/include/atlctrls.h @@ -0,0 +1,10039 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLCTRLS_H__ +#define __ATLCTRLS_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlctrls.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlctrls.h requires atlwin.h to be included first +#endif + +#if (_WIN32_IE < 0x0300) + #error atlctrls.h requires IE Version 3.0 or higher +#endif + +#ifndef _WIN32_WCE + #include + #include +#elif defined(WIN32_PLATFORM_WFSP) && !defined(_WINUSERM_H_) + #include +#endif // !_WIN32_WCE + +// protect template members from windowsx.h macros +#ifdef _INC_WINDOWSX + #undef GetNextSibling + #undef GetPrevSibling +#endif // _INC_WINDOWSX + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CStaticT - CStatic +// CButtonT - CButton +// CListBoxT - CListBox +// CComboBoxT - CComboBox +// CEditT - CEdit +// CEditCommands +// CScrollBarT - CScrollBar +// +// CImageList +// CListViewCtrlT - CListViewCtrl +// CTreeViewCtrlT - CTreeViewCtrl +// CTreeItemT - CTreeItem +// CTreeViewCtrlExT - CTreeViewCtrlEx +// CHeaderCtrlT - CHeaderCtrl +// CToolBarCtrlT - CToolBarCtrl +// CStatusBarCtrlT - CStatusBarCtrl +// CTabCtrlT - CTabCtrl +// CToolInfo +// CToolTipCtrlT - CToolTipCtrl +// CTrackBarCtrlT - CTrackBarCtrl +// CUpDownCtrlT - CUpDownCtrl +// CProgressBarCtrlT - CProgressBarCtrl +// CHotKeyCtrlT - CHotKeyCtrl +// CAnimateCtrlT - CAnimateCtrl +// CRichEditCtrlT - CRichEditCtrl +// CRichEditCommands +// CDragListBoxT - CDragListBox +// CDragListNotifyImpl +// CReBarCtrlT - CReBarCtrl +// CComboBoxExT - CComboBoxEx +// CDateTimePickerCtrlT - CDateTimePickerCtrl +// CMonthCalendarCtrlT - CMonthCalendarCtrl +// CFlatScrollBarImpl +// CFlatScrollBarT - CFlatScrollBar +// CIPAddressCtrlT - CIPAddressCtrl +// CPagerCtrlT - CPagerCtrl +// CLinkCtrlT - CLinkCtrl +// +// CCustomDraw +// +// CCECommandBarCtrlT - CCECommandBarCtrl +// CCECommandBandsCtrlT - CCECommandBandsCtrl + + +namespace WTL +{ + +// These are wrapper classes for Windows standard and common controls. +// To implement a window based on a control, use following: +// Example: Implementing a window based on a list box +// +// class CMyListBox : CWindowImpl +// { +// public: +// BEGIN_MSG_MAP(CMyListBox) +// // put your message handler entries here +// END_MSG_MAP() +// }; + + + +// --- Standard Windows controls --- + +/////////////////////////////////////////////////////////////////////////////// +// CStatic - client side for a Windows STATIC control + +template +class CStaticT : public TBase +{ +public: +// Constructors + CStaticT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CStaticT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("STATIC"); + } + +#ifndef _WIN32_WCE + HICON GetIcon() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, STM_GETICON, 0, 0L); + } + + HICON SetIcon(HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, STM_SETICON, (WPARAM)hIcon, 0L); + } + + HENHMETAFILE GetEnhMetaFile() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HENHMETAFILE)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ENHMETAFILE, 0L); + } + + HENHMETAFILE SetEnhMetaFile(HENHMETAFILE hMetaFile) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HENHMETAFILE)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ENHMETAFILE, (LPARAM)hMetaFile); + } +#else // CE specific + HICON GetIcon() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ICON, 0L); + } + + HICON SetIcon(HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + } +#endif // _WIN32_WCE + + CBitmapHandle GetBitmap() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_BITMAP, 0L)); + } + + CBitmapHandle SetBitmap(HBITMAP hBitmap) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap)); + } + + HCURSOR GetCursor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HCURSOR)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_CURSOR, 0L); + } + + HCURSOR SetCursor(HCURSOR hCursor) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HCURSOR)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_CURSOR, (LPARAM)hCursor); + } +}; + +typedef CStaticT CStatic; + + +/////////////////////////////////////////////////////////////////////////////// +// CButton - client side for a Windows BUTTON control + +template +class CButtonT : public TBase +{ +public: +// Constructors + CButtonT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CButtonT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("BUTTON"); + } + + UINT GetState() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, BM_GETSTATE, 0, 0L); + } + + void SetState(BOOL bHighlight) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_SETSTATE, bHighlight, 0L); + } + + int GetCheck() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, BM_GETCHECK, 0, 0L); + } + + void SetCheck(int nCheck) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_SETCHECK, nCheck, 0L); + } + + UINT GetButtonStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::GetWindowLong(m_hWnd, GWL_STYLE) & 0xFFFF; + } + + void SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_SETSTYLE, nStyle, (LPARAM)bRedraw); + } + +#ifndef _WIN32_WCE + HICON GetIcon() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_ICON, 0L); + } + + HICON SetIcon(HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HICON)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + } + + CBitmapHandle GetBitmap() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_BITMAP, 0L)); + } + + CBitmapHandle SetBitmap(HBITMAP hBitmap) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap)); + } +#endif // !_WIN32_WCE + +#if (_WIN32_WINNT >= 0x0501) + BOOL GetIdealSize(LPSIZE lpSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_GETIDEALSIZE, 0, (LPARAM)lpSize); + } + + BOOL GetImageList(PBUTTON_IMAGELIST pButtonImagelist) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_GETIMAGELIST, 0, (LPARAM)pButtonImagelist); + } + + BOOL SetImageList(PBUTTON_IMAGELIST pButtonImagelist) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_SETIMAGELIST, 0, (LPARAM)pButtonImagelist); + } + + BOOL GetTextMargin(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_GETTEXTMARGIN, 0, (LPARAM)lpRect); + } + + BOOL SetTextMargin(LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, BCM_SETTEXTMARGIN, 0, (LPARAM)lpRect); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (WINVER >= 0x0600) + void SetDontClick(BOOL bDontClick) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_SETDONTCLICK, (WPARAM)bDontClick, 0L); + } +#endif // (WINVER >= 0x0600) + +#if (_WIN32_WINNT >= 0x0600) + BOOL SetDropDownState(BOOL bDropDown) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_SETDROPDOWNSTATE, (WPARAM)bDropDown, 0L); + } + + BOOL GetSplitInfo(PBUTTON_SPLITINFO pSplitInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_GETSPLITINFO, 0, (LPARAM)pSplitInfo); + } + + BOOL SetSplitInfo(PBUTTON_SPLITINFO pSplitInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_SETSPLITINFO, 0, (LPARAM)pSplitInfo); + } + + int GetNoteLength() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0); + return (int)::SendMessage(m_hWnd, BCM_GETNOTELENGTH, 0, 0L); + } + + BOOL GetNote(LPWSTR lpstrNoteText, int cchNoteText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_GETNOTE, cchNoteText, (LPARAM)lpstrNoteText); + } + + BOOL SetNote(LPCWSTR lpstrNoteText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0); + return (BOOL)::SendMessage(m_hWnd, BCM_SETNOTE, 0, (LPARAM)lpstrNoteText); + } + + LRESULT SetElevationRequiredState(BOOL bSet) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::SendMessage(m_hWnd, BCM_SETSHIELD, 0, (LPARAM)bSet); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + void Click() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, BM_CLICK, 0, 0L); + } +}; + +typedef CButtonT CButton; + + +/////////////////////////////////////////////////////////////////////////////// +// CListBox - client side for a Windows LISTBOX control + +template +class CListBoxT : public TBase +{ +public: +// Constructors + CListBoxT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CListBoxT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("LISTBOX"); + } + + // for entire listbox + int GetCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETCOUNT, 0, 0L); + } + +#ifndef _WIN32_WCE + int SetCount(int cItems) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(((GetStyle() & LBS_NODATA) != 0) && ((GetStyle() & LBS_HASSTRINGS) == 0)); + return (int)::SendMessage(m_hWnd, LB_SETCOUNT, cItems, 0L); + } +#endif // !_WIN32_WCE + + int GetHorizontalExtent() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETHORIZONTALEXTENT, 0, 0L); + } + + void SetHorizontalExtent(int cxExtent) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LB_SETHORIZONTALEXTENT, cxExtent, 0L); + } + + int GetTopIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETTOPINDEX, 0, 0L); + } + + int SetTopIndex(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SETTOPINDEX, nIndex, 0L); + } + + LCID GetLocale() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LCID)::SendMessage(m_hWnd, LB_GETLOCALE, 0, 0L); + } + + LCID SetLocale(LCID nNewLocale) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LCID)::SendMessage(m_hWnd, LB_SETLOCALE, (WPARAM)nNewLocale, 0L); + } + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + DWORD GetListBoxInfo() const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_WIN32_WINNT >= 0x0501) + return (DWORD)::SendMessage(m_hWnd, LB_GETLISTBOXINFO, 0, 0L); +#else // !(_WIN32_WINNT >= 0x0501) + return ::GetListBoxInfo(m_hWnd); +#endif // !(_WIN32_WINNT >= 0x0501) + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + + // for single-selection listboxes + int GetCurSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0); + return (int)::SendMessage(m_hWnd, LB_GETCURSEL, 0, 0L); + } + + int SetCurSel(int nSelect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0); + return (int)::SendMessage(m_hWnd, LB_SETCURSEL, nSelect, 0L); + } + + // for multiple-selection listboxes + int GetSel(int nIndex) const // also works for single-selection + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETSEL, nIndex, 0L); + } + + int SetSel(int nIndex, BOOL bSelect = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + return (int)::SendMessage(m_hWnd, LB_SETSEL, bSelect, nIndex); + } + + int GetSelCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + return (int)::SendMessage(m_hWnd, LB_GETSELCOUNT, 0, 0L); + } + + int GetSelItems(int nMaxItems, LPINT rgIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + return (int)::SendMessage(m_hWnd, LB_GETSELITEMS, nMaxItems, (LPARAM)rgIndex); + } + + int GetAnchorIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + return (int)::SendMessage(m_hWnd, LB_GETANCHORINDEX, 0, 0L); + } + + void SetAnchorIndex(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + ::SendMessage(m_hWnd, LB_SETANCHORINDEX, nIndex, 0L); + } + + int GetCaretIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETCARETINDEX, 0, 0); + } + + int SetCaretIndex(int nIndex, BOOL bScroll = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SETCARETINDEX, nIndex, MAKELONG(bScroll, 0)); + } + + // for listbox items + DWORD_PTR GetItemData(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD_PTR)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L); + } + + int SetItemData(int nIndex, DWORD_PTR dwItemData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SETITEMDATA, nIndex, (LPARAM)dwItemData); + } + + void* GetItemDataPtr(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (void*)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L); + } + + int SetItemDataPtr(int nIndex, void* pData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItemData(nIndex, (DWORD_PTR)pData); + } + + int GetItemRect(int nIndex, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETITEMRECT, nIndex, (LPARAM)lpRect); + } + + int GetText(int nIndex, LPTSTR lpszBuffer) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETTEXT, nIndex, (LPARAM)lpszBuffer); + } + +#ifndef _ATL_NO_COM +#ifdef _OLEAUTO_H_ + BOOL GetTextBSTR(int nIndex, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + + int nLen = GetTextLen(nIndex); + if(nLen == LB_ERR) + return FALSE; + + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(nLen + 1); + if(lpstrText == NULL) + return FALSE; + + if(GetText(nIndex, lpstrText) == LB_ERR) + return FALSE; + + bstrText = ::SysAllocString(T2OLE(lpstrText)); + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // _OLEAUTO_H_ +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetText(int nIndex, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int cchLen = GetTextLen(nIndex); + if(cchLen == LB_ERR) + return LB_ERR; + int nRet = LB_ERR; + LPTSTR lpstr = strText.GetBufferSetLength(cchLen); + if(lpstr != NULL) + { + nRet = GetText(nIndex, lpstr); + strText.ReleaseBuffer(); + } + return nRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + int GetTextLen(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETTEXTLEN, nIndex, 0L); + } + + int GetItemHeight(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_GETITEMHEIGHT, nIndex, 0L); + } + + int SetItemHeight(int nIndex, UINT cyItemHeight) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0)); + } + + // Settable only attributes + void SetColumnWidth(int cxWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LB_SETCOLUMNWIDTH, cxWidth, 0L); + } + + BOOL SetTabStops(int nTabStops, LPINT rgTabStops) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0); + return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops); + } + + BOOL SetTabStops() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0); + return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 0, 0L); + } + + BOOL SetTabStops(const int& cxEachStop) // takes an 'int' + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0); + return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop); + } + +// Operations + int InitStorage(int nItems, UINT nBytes) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_INITSTORAGE, (WPARAM)nItems, nBytes); + } + + void ResetContent() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LB_RESETCONTENT, 0, 0L); + } + + UINT ItemFromPoint(POINT pt, BOOL& bOutside) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dw = (DWORD)::SendMessage(m_hWnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y)); + bOutside = (BOOL)HIWORD(dw); + return (UINT)LOWORD(dw); + } + + // manipulating listbox items + int AddString(LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_ADDSTRING, 0, (LPARAM)lpszItem); + } + + int DeleteString(UINT nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_DELETESTRING, nIndex, 0L); + } + + int InsertString(int nIndex, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_INSERTSTRING, nIndex, (LPARAM)lpszItem); + } + +#ifndef _WIN32_WCE + int Dir(UINT attr, LPCTSTR lpszWildCard) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_DIR, attr, (LPARAM)lpszWildCard); + } + + int AddFile(LPCTSTR lpstrFileName) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_ADDFILE, 0, (LPARAM)lpstrFileName); + } +#endif // !_WIN32_WCE + + // selection helpers + int FindString(int nStartAfter, LPCTSTR lpszItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_FINDSTRING, nStartAfter, (LPARAM)lpszItem); + } + + int FindStringExact(int nIndexStart, LPCTSTR lpszFind) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind); + } + + int SelectString(int nStartAfter, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LB_SELECTSTRING, nStartAfter, (LPARAM)lpszItem); + } + + int SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); + ATLASSERT(nFirstItem <= nLastItem); + return bSelect ? (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nFirstItem, nLastItem) : (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nLastItem, nFirstItem); + } + +#ifdef WIN32_PLATFORM_WFSP // SmartPhone only messages + DWORD GetInputMode(BOOL bCurrentMode = TRUE) + { + return SendMessage(LB_GETINPUTMODE, 0, (LPARAM)bCurrentMode); + } + + BOOL SetInputMode(DWORD dwMode) + { + return SendMessage(LB_SETINPUTMODE, 0, (LPARAM)dwMode); + } +#endif // WIN32_PLATFORM_WFSP +}; + +typedef CListBoxT CListBox; + + +/////////////////////////////////////////////////////////////////////////////// +// CComboBox - client side for a Windows COMBOBOX control + +#ifndef WIN32_PLATFORM_WFSP // No COMBOBOX on SmartPhones + +template +class CComboBoxT : public TBase +{ +public: +// Constructors + CComboBoxT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CComboBoxT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("COMBOBOX"); + } + + // for entire combo box + int GetCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETCOUNT, 0, 0L); + } + + int GetCurSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETCURSEL, 0, 0L); + } + + int SetCurSel(int nSelect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETCURSEL, nSelect, 0L); + } + + LCID GetLocale() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LCID)::SendMessage(m_hWnd, CB_GETLOCALE, 0, 0L); + } + + LCID SetLocale(LCID nNewLocale) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LCID)::SendMessage(m_hWnd, CB_SETLOCALE, (WPARAM)nNewLocale, 0L); + } + + int GetTopIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETTOPINDEX, 0, 0L); + } + + int SetTopIndex(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETTOPINDEX, nIndex, 0L); + } + + UINT GetHorizontalExtent() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, CB_GETHORIZONTALEXTENT, 0, 0L); + } + + void SetHorizontalExtent(UINT nExtent) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CB_SETHORIZONTALEXTENT, nExtent, 0L); + } + + int GetDroppedWidth() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETDROPPEDWIDTH, 0, 0L); + } + + int SetDroppedWidth(UINT nWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETDROPPEDWIDTH, nWidth, 0L); + } + +#if ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + BOOL GetComboBoxInfo(PCOMBOBOXINFO pComboBoxInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if ((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + return (BOOL)::SendMessage(m_hWnd, CB_GETCOMBOBOXINFO, 0, (LPARAM)pComboBoxInfo); +#else // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + return ::GetComboBoxInfo(m_hWnd, pComboBoxInfo); +#endif // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + } +#endif // ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) + + // for edit control + DWORD GetEditSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, CB_GETEDITSEL, 0, 0L); + } + + BOOL SetEditSel(int nStartChar, int nEndChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_SETEDITSEL, 0, MAKELONG(nStartChar, nEndChar)); + } + + // for combobox item + DWORD_PTR GetItemData(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD_PTR)::SendMessage(m_hWnd, CB_GETITEMDATA, nIndex, 0L); + } + + int SetItemData(int nIndex, DWORD_PTR dwItemData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETITEMDATA, nIndex, (LPARAM)dwItemData); + } + + void* GetItemDataPtr(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (void*)GetItemData(nIndex); + } + + int SetItemDataPtr(int nIndex, void* pData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItemData(nIndex, (DWORD_PTR)pData); + } + + int GetLBText(int nIndex, LPTSTR lpszText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETLBTEXT, nIndex, (LPARAM)lpszText); + } + +#ifndef _ATL_NO_COM + BOOL GetLBTextBSTR(int nIndex, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + + int nLen = GetLBTextLen(nIndex); + if(nLen == CB_ERR) + return FALSE; + + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(nLen + 1); + if(lpstrText == NULL) + return FALSE; + + if(GetLBText(nIndex, lpstrText) == CB_ERR) + return FALSE; + + bstrText = ::SysAllocString(T2OLE(lpstrText)); + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetLBText(int nIndex, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int cchLen = GetLBTextLen(nIndex); + if(cchLen == CB_ERR) + return CB_ERR; + int nRet = CB_ERR; + LPTSTR lpstr = strText.GetBufferSetLength(cchLen); + if(lpstr != NULL) + { + nRet = GetLBText(nIndex, lpstr); + strText.ReleaseBuffer(); + } + return nRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + int GetLBTextLen(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETLBTEXTLEN, nIndex, 0L); + } + + int GetItemHeight(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETITEMHEIGHT, nIndex, 0L); + } + + int SetItemHeight(int nIndex, UINT cyItemHeight) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0)); + } + + BOOL GetExtendedUI() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_GETEXTENDEDUI, 0, 0L); + } + + int SetExtendedUI(BOOL bExtended = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SETEXTENDEDUI, bExtended, 0L); + } + + void GetDroppedControlRect(LPRECT lprect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)lprect); + } + + BOOL GetDroppedState() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_GETDROPPEDSTATE, 0, 0L); + } + +#if (_WIN32_WINNT >= 0x0501) + int GetMinVisible() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_GETMINVISIBLE, 0, 0L); + } + + BOOL SetMinVisible(int nMinVisible) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_SETMINVISIBLE, nMinVisible, 0L); + } + + // Vista only + BOOL GetCueBannerText(LPWSTR lpwText, int cchText) const + { +#ifndef CB_GETCUEBANNER + const UINT CB_GETCUEBANNER = (CBM_FIRST + 4); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_GETCUEBANNER, (WPARAM)lpwText, cchText); + } + + // Vista only + BOOL SetCueBannerText(LPCWSTR lpcwText) + { +#ifndef CB_SETCUEBANNER + const UINT CB_SETCUEBANNER = (CBM_FIRST + 3); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_SETCUEBANNER, 0, (LPARAM)lpcwText); + } +#endif // (_WIN32_WINNT >= 0x0501) + +// Operations + int InitStorage(int nItems, UINT nBytes) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_INITSTORAGE, (WPARAM)nItems, nBytes); + } + + void ResetContent() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CB_RESETCONTENT, 0, 0L); + } + + // for edit control + BOOL LimitText(int nMaxChars) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CB_LIMITTEXT, nMaxChars, 0L); + } + + // for drop-down combo boxes + void ShowDropDown(BOOL bShowIt = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CB_SHOWDROPDOWN, bShowIt, 0L); + } + + // manipulating listbox items + int AddString(LPCTSTR lpszString) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_ADDSTRING, 0, (LPARAM)lpszString); + } + + int DeleteString(UINT nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_DELETESTRING, nIndex, 0L); + } + + int InsertString(int nIndex, LPCTSTR lpszString) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_INSERTSTRING, nIndex, (LPARAM)lpszString); + } + +#ifndef _WIN32_WCE + int Dir(UINT attr, LPCTSTR lpszWildCard) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_DIR, attr, (LPARAM)lpszWildCard); + } +#endif // !_WIN32_WCE + + // selection helpers + int FindString(int nStartAfter, LPCTSTR lpszString) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_FINDSTRING, nStartAfter, (LPARAM)lpszString); + } + + int FindStringExact(int nIndexStart, LPCTSTR lpszFind) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind); + } + + int SelectString(int nStartAfter, LPCTSTR lpszString) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CB_SELECTSTRING, nStartAfter, (LPARAM)lpszString); + } + + // Clipboard operations + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); + } + + void Copy() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_COPY, 0, 0L); + } + + void Cut() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CUT, 0, 0L); + } + + void Paste() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); + } +}; + +typedef CComboBoxT CComboBox; + +#endif // !WIN32_PLATFORM_WFSP + +/////////////////////////////////////////////////////////////////////////////// +// CEdit - client side for a Windows EDIT control + +template +class CEditT : public TBase +{ +public: +// Constructors + CEditT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CEditT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("EDIT"); + } + + BOOL CanUndo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L); + } + + int GetLineCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L); + } + + BOOL GetModify() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L); + } + + void SetModify(BOOL bModified = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L); + } + + void GetRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect); + } + + DWORD GetSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L); + } + + void GetSel(int& nStartChar, int& nEndChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); + } + +#ifndef _WIN32_WCE + HLOCAL GetHandle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HLOCAL)::SendMessage(m_hWnd, EM_GETHANDLE, 0, 0L); + } + + void SetHandle(HLOCAL hBuffer) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETHANDLE, (WPARAM)hBuffer, 0L); + } +#endif // !_WIN32_WCE + + DWORD GetMargins() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETMARGINS, 0, 0L); + } + + void SetMargins(UINT nLeft, UINT nRight) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELONG(nLeft, nRight)); + } + + UINT GetLimitText() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L); + } + + void SetLimitText(UINT nMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETLIMITTEXT, nMax, 0L); + } + + POINT PosFromChar(UINT nChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_POSFROMCHAR, nChar, 0); + POINT point = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) }; + return point; + } + + int CharFromPos(POINT pt, int* pLine = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y)); + if(pLine != NULL) + *pLine = (int)(short)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + + // NOTE: first word in lpszBuffer must contain the size of the buffer! + int GetLine(int nIndex, LPTSTR lpszBuffer) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); + } + + int GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + *(LPWORD)lpszBuffer = (WORD)nMaxLength; + return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); + } + + TCHAR GetPasswordChar() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (TCHAR)::SendMessage(m_hWnd, EM_GETPASSWORDCHAR, 0, 0L); + } + + void SetPasswordChar(TCHAR ch) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETPASSWORDCHAR, ch, 0L); + } + +#ifndef _WIN32_WCE + EDITWORDBREAKPROC GetWordBreakProc() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (EDITWORDBREAKPROC)::SendMessage(m_hWnd, EM_GETWORDBREAKPROC, 0, 0L); + } + + void SetWordBreakProc(EDITWORDBREAKPROC ewbprc) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETWORDBREAKPROC, 0, (LPARAM)ewbprc); + } +#endif // !_WIN32_WCE + + int GetFirstVisibleLine() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L); + } + +#ifndef _WIN32_WCE + int GetThumb() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & ES_MULTILINE) != 0); + return (int)::SendMessage(m_hWnd, EM_GETTHUMB, 0, 0L); + } +#endif // !_WIN32_WCE + + BOOL SetReadOnly(BOOL bReadOnly = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L); + } + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + UINT GetImeStatus(UINT uStatus) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETIMESTATUS, uStatus, 0L); + } + + UINT SetImeStatus(UINT uStatus, UINT uData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_SETIMESTATUS, uStatus, uData); + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) + BOOL GetCueBannerText(LPCWSTR lpstrText, int cchText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETCUEBANNER, (WPARAM)lpstrText, cchText); + } + + // bKeepWithFocus - Vista only + BOOL SetCueBannerText(LPCWSTR lpstrText, BOOL bKeepWithFocus = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETCUEBANNER, (WPARAM)bKeepWithFocus, (LPARAM)(lpstrText)); + } +#endif // (_WIN32_WINNT >= 0x0501) + +// Operations + void EmptyUndoBuffer() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L); + } + + BOOL FmtLines(BOOL bAddEOL) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_FMTLINES, bAddEOL, 0L); + } + + void LimitText(int nChars = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_LIMITTEXT, nChars, 0L); + } + + int LineFromChar(int nIndex = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINEFROMCHAR, nIndex, 0L); + } + + int LineIndex(int nLine = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L); + } + + int LineLength(int nLine = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L); + } + + void LineScroll(int nLines, int nChars = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_LINESCROLL, nChars, nLines); + } + + void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText); + } + + void SetRect(LPCRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect); + } + + void SetRectNP(LPCRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETRECTNP, 0, (LPARAM)lpRect); + } + + void SetSel(DWORD dwSelection, BOOL bNoScroll = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETSEL, LOWORD(dwSelection), HIWORD(dwSelection)); + if(!bNoScroll) + ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); + } + + void SetSel(int nStartChar, int nEndChar, BOOL bNoScroll = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar); + if(!bNoScroll) + ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); + } + + void SetSelAll(BOOL bNoScroll = FALSE) + { + SetSel(0, -1, bNoScroll); + } + + void SetSelNone(BOOL bNoScroll = FALSE) + { + SetSel(-1, 0, bNoScroll); + } + + BOOL SetTabStops(int nTabStops, LPINT rgTabStops) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops); + } + + BOOL SetTabStops() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L); + } + + BOOL SetTabStops(const int& cxEachStop) // takes an 'int' + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop); + } + + void ScrollCaret() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); + } + + int Scroll(int nScrollAction) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & ES_MULTILINE) != 0); + LRESULT lRet = ::SendMessage(m_hWnd, EM_SCROLL, nScrollAction, 0L); + if(!(BOOL)HIWORD(lRet)) + return -1; // failed + return (int)(short)LOWORD(lRet); + + } + + void InsertText(int nInsertAfterChar, LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE) + { + SetSel(nInsertAfterChar, nInsertAfterChar, bNoScroll); + ReplaceSel(lpstrText, bCanUndo); + } + + void AppendText(LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE) + { + InsertText(GetWindowTextLength(), lpstrText, bNoScroll, bCanUndo); + } + +#if (_WIN32_WINNT >= 0x0501) + BOOL ShowBalloonTip(PEDITBALLOONTIP pEditBaloonTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SHOWBALLOONTIP, 0, (LPARAM)pEditBaloonTip); + } + + BOOL HideBalloonTip() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_HIDEBALLOONTIP, 0, 0L); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + DWORD GetHilite() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L); + } + + void GetHilite(int& nStartChar, int& nEndChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L); + nStartChar = (int)(short)LOWORD(dwRet); + nEndChar = (int)(short)HIWORD(dwRet); + } + + void SetHilite(int nStartChar, int nEndChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETHILITE, nStartChar, nEndChar); + } +#endif // (_WIN32_WINNT >= 0x0600) + + // Clipboard operations + BOOL Undo() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L); + } + + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); + } + + void Copy() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_COPY, 0, 0L); + } + + void Cut() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CUT, 0, 0L); + } + + void Paste() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); + } + +#ifdef WIN32_PLATFORM_WFSP // SmartPhone only messages + DWORD GetExtendedStyle() + { + return SendMessage(EM_GETEXTENDEDSTYLE); + } + + DWORD SetExtendedStyle(DWORD dwMask, DWORD dwExStyle) + { + return SendMessage(EM_SETEXTENDEDSTYLE, (WPARAM)dwMask, (LPARAM)dwExStyle); + } + + DWORD GetInputMode(BOOL bCurrentMode = TRUE) + { + return SendMessage(EM_GETINPUTMODE, 0, (LPARAM)bCurrentMode); + } + + BOOL SetInputMode(DWORD dwMode) + { + return SendMessage(EM_SETINPUTMODE, 0, (LPARAM)dwMode); + } + + BOOL SetSymbols(LPCTSTR szSymbols) + { + return SendMessage(EM_SETSYMBOLS, 0, (LPARAM)szSymbols); + } + + BOOL ResetSymbols() + { + return SendMessage(EM_SETSYMBOLS); + } +#endif // WIN32_PLATFORM_WFSP +}; + +typedef CEditT CEdit; + + +/////////////////////////////////////////////////////////////////////////////// +// CEditCommands - message handlers for standard EDIT commands + +// Chain to CEditCommands message map. Your class must also derive from CEdit. +// Example: +// class CMyEdit : public CWindowImpl, +// public CEditCommands +// { +// public: +// BEGIN_MSG_MAP(CMyEdit) +// // your handlers... +// CHAIN_MSG_MAP_ALT(CEditCommands, 1) +// END_MSG_MAP() +// // other stuff... +// }; + +template +class CEditCommands +{ +public: + BEGIN_MSG_MAP(CEditCommands< T >) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_EDIT_CLEAR, OnEditClear) + COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, OnEditClearAll) + COMMAND_ID_HANDLER(ID_EDIT_COPY, OnEditCopy) + COMMAND_ID_HANDLER(ID_EDIT_CUT, OnEditCut) + COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnEditPaste) + COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnEditSelectAll) + COMMAND_ID_HANDLER(ID_EDIT_UNDO, OnEditUndo) + END_MSG_MAP() + + LRESULT OnEditClear(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Clear(); + return 0; + } + + LRESULT OnEditClearAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->SetSel(0, -1); + pT->Clear(); + return 0; + } + + LRESULT OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Copy(); + return 0; + } + + LRESULT OnEditCut(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Cut(); + return 0; + } + + LRESULT OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Paste(); + return 0; + } + + LRESULT OnEditSelectAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->SetSel(0, -1); + return 0; + } + + LRESULT OnEditUndo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Undo(); + return 0; + } + +// State (update UI) helpers + BOOL CanCut() const + { return HasSelection(); } + + BOOL CanCopy() const + { return HasSelection(); } + + BOOL CanClear() const + { return HasSelection(); } + + BOOL CanSelectAll() const + { return HasText(); } + + BOOL CanFind() const + { return HasText(); } + + BOOL CanRepeat() const + { return HasText(); } + + BOOL CanReplace() const + { return HasText(); } + + BOOL CanClearAll() const + { return HasText(); } + +// Implementation + BOOL HasSelection() const + { + const T* pT = static_cast(this); + int nMin, nMax; + ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nMin, (LPARAM)&nMax); + return (nMin != nMax); + } + + BOOL HasText() const + { + const T* pT = static_cast(this); + return (pT->GetWindowTextLength() > 0); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CScrollBar - client side for a Windows SCROLLBAR control + +template +class CScrollBarT : public TBase +{ +public: +// Constructors + CScrollBarT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CScrollBarT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return _T("SCROLLBAR"); + } + +#ifndef _WIN32_WCE + int GetScrollPos() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::GetScrollPos(m_hWnd, SB_CTL); + } +#endif // !_WIN32_WCE + + int SetScrollPos(int nPos, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::SetScrollPos(m_hWnd, SB_CTL, nPos, bRedraw); + } + +#ifndef _WIN32_WCE + void GetScrollRange(LPINT lpMinPos, LPINT lpMaxPos) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::GetScrollRange(m_hWnd, SB_CTL, lpMinPos, lpMaxPos); + } +#endif // !_WIN32_WCE + + void SetScrollRange(int nMinPos, int nMaxPos, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SetScrollRange(m_hWnd, SB_CTL, nMinPos, nMaxPos, bRedraw); + } + + BOOL GetScrollInfo(LPSCROLLINFO lpScrollInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::GetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo); + } + + int SetScrollInfo(LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::SetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo, bRedraw); + } + +#ifndef _WIN32_WCE + int GetScrollLimit() const + { + int nMin = 0, nMax = 0; + ::GetScrollRange(m_hWnd, SB_CTL, &nMin, &nMax); + SCROLLINFO info = { 0 }; + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_PAGE; + if(::GetScrollInfo(m_hWnd, SB_CTL, &info)) + nMax -= ((info.nPage - 1) > 0) ? (info.nPage - 1) : 0; + + return nMax; + } + +#if (WINVER >= 0x0500) + BOOL GetScrollBarInfo(PSCROLLBARINFO pScrollBarInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_WIN32_WINNT >= 0x0501) + return (BOOL)::SendMessage(m_hWnd, SBM_GETSCROLLBARINFO, 0, (LPARAM)pScrollBarInfo); +#else // !(_WIN32_WINNT >= 0x0501) + return ::GetScrollBarInfo(m_hWnd, OBJID_CLIENT, pScrollBarInfo); +#endif // !(_WIN32_WINNT >= 0x0501) + } +#endif // (WINVER >= 0x0500) + +// Operations + void ShowScrollBar(BOOL bShow = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::ShowScrollBar(m_hWnd, SB_CTL, bShow); + } + + BOOL EnableScrollBar(UINT nArrowFlags = ESB_ENABLE_BOTH) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::EnableScrollBar(m_hWnd, SB_CTL, nArrowFlags); + } +#endif // !_WIN32_WCE +}; + +typedef CScrollBarT CScrollBar; + + +// --- Windows Common Controls --- + +/////////////////////////////////////////////////////////////////////////////// +// CImageList + +class CImageList +{ +public: + HIMAGELIST m_hImageList; + +// Constructor + CImageList(HIMAGELIST hImageList = NULL) : m_hImageList(hImageList) + { } + +// Operators, etc. + CImageList& operator =(HIMAGELIST hImageList) + { + m_hImageList = hImageList; + return *this; + } + + operator HIMAGELIST() const { return m_hImageList; } + + void Attach(HIMAGELIST hImageList) + { + ATLASSERT(m_hImageList == NULL); + ATLASSERT(hImageList != NULL); + m_hImageList = hImageList; + } + + HIMAGELIST Detach() + { + HIMAGELIST hImageList = m_hImageList; + m_hImageList = NULL; + return hImageList; + } + + bool IsNull() const { return (m_hImageList == NULL); } + +// Attributes + int GetImageCount() const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetImageCount(m_hImageList); + } + + COLORREF GetBkColor() const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetBkColor(m_hImageList); + } + + COLORREF SetBkColor(COLORREF cr) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetBkColor(m_hImageList, cr); + } + + BOOL GetImageInfo(int nImage, IMAGEINFO* pImageInfo) const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetImageInfo(m_hImageList, nImage, pImageInfo); + } + + HICON GetIcon(int nIndex, UINT uFlags = ILD_NORMAL) const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetIcon(m_hImageList, nIndex, uFlags); + } + + BOOL GetIconSize(int& cx, int& cy) const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetIconSize(m_hImageList, &cx, &cy); + } + + BOOL GetIconSize(SIZE& size) const + { + ATLASSERT(m_hImageList != NULL); + return ImageList_GetIconSize(m_hImageList, (int*)&size.cx, (int*)&size.cy); + } + + BOOL SetIconSize(int cx, int cy) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetIconSize(m_hImageList, cx, cy); + } + + BOOL SetIconSize(SIZE size) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetIconSize(m_hImageList, size.cx, size.cy); + } + + BOOL SetImageCount(UINT uNewCount) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetImageCount(m_hImageList, uNewCount); + } + + BOOL SetOverlayImage(int nImage, int nOverlay) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetOverlayImage(m_hImageList, nImage, nOverlay); + } + +// Operations + BOOL Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_Create(cx, cy, nFlags, nInitial, nGrow); + return (m_hImageList != NULL) ? TRUE : FALSE; + } + + BOOL Create(ATL::_U_STRINGorID bitmap, int cx, int nGrow, COLORREF crMask) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, cx, nGrow, crMask); + return (m_hImageList != NULL) ? TRUE : FALSE; + } + + BOOL CreateFromImage(ATL::_U_STRINGorID image, int cx, int nGrow, COLORREF crMask, UINT uType, UINT uFlags = LR_DEFAULTCOLOR | LR_DEFAULTSIZE) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, cx, nGrow, crMask, uType, uFlags); + return (m_hImageList != NULL) ? TRUE : FALSE; + } + + BOOL Merge(HIMAGELIST hImageList1, int nImage1, HIMAGELIST hImageList2, int nImage2, int dx, int dy) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_Merge(hImageList1, nImage1, hImageList2, nImage2, dx, dy); + return (m_hImageList != NULL) ? TRUE : FALSE; + } + +#ifndef _WIN32_WCE +#ifdef __IStream_INTERFACE_DEFINED__ + BOOL CreateFromStream(LPSTREAM lpStream) + { + ATLASSERT(m_hImageList == NULL); + m_hImageList = ImageList_Read(lpStream); + return (m_hImageList != NULL) ? TRUE : FALSE; + } +#endif // __IStream_INTERFACE_DEFINED__ +#endif // !_WIN32_WCE + + BOOL Destroy() + { + if (m_hImageList == NULL) + return FALSE; + BOOL bRet = ImageList_Destroy(m_hImageList); + if(bRet) + m_hImageList = NULL; + return bRet; + } + + int Add(HBITMAP hBitmap, HBITMAP hBitmapMask = NULL) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Add(m_hImageList, hBitmap, hBitmapMask); + } + + int Add(HBITMAP hBitmap, COLORREF crMask) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_AddMasked(m_hImageList, hBitmap, crMask); + } + + BOOL Remove(int nImage) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Remove(m_hImageList, nImage); + } + + BOOL RemoveAll() + { + ATLASSERT(m_hImageList != NULL); + return ImageList_RemoveAll(m_hImageList); + } + + BOOL Replace(int nImage, HBITMAP hBitmap, HBITMAP hBitmapMask) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Replace(m_hImageList, nImage, hBitmap, hBitmapMask); + } + + int AddIcon(HICON hIcon) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_AddIcon(m_hImageList, hIcon); + } + + int ReplaceIcon(int nImage, HICON hIcon) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_ReplaceIcon(m_hImageList, nImage, hIcon); + } + + HICON ExtractIcon(int nImage) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_ExtractIcon(NULL, m_hImageList, nImage); + } + + BOOL Draw(HDC hDC, int nImage, int x, int y, UINT nStyle) + { + ATLASSERT(m_hImageList != NULL); + ATLASSERT(hDC != NULL); + return ImageList_Draw(m_hImageList, nImage, hDC, x, y, nStyle); + } + + BOOL Draw(HDC hDC, int nImage, POINT pt, UINT nStyle) + { + ATLASSERT(m_hImageList != NULL); + ATLASSERT(hDC != NULL); + return ImageList_Draw(m_hImageList, nImage, hDC, pt.x, pt.y, nStyle); + } + + BOOL DrawEx(int nImage, HDC hDC, int x, int y, int dx, int dy, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle) + { + ATLASSERT(m_hImageList != NULL); + ATLASSERT(hDC != NULL); + return ImageList_DrawEx(m_hImageList, nImage, hDC, x, y, dx, dy, rgbBk, rgbFg, fStyle); + } + + BOOL DrawEx(int nImage, HDC hDC, RECT& rect, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle) + { + ATLASSERT(m_hImageList != NULL); + ATLASSERT(hDC != NULL); + return ImageList_DrawEx(m_hImageList, nImage, hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, rgbBk, rgbFg, fStyle); + } + + static BOOL DrawIndirect(IMAGELISTDRAWPARAMS* pimldp) + { + return ImageList_DrawIndirect(pimldp); + } + + BOOL Copy(int nSrc, int nDst, UINT uFlags = ILCF_MOVE) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Copy(m_hImageList, nDst, m_hImageList, nSrc, uFlags); + } + +#ifdef __IStream_INTERFACE_DEFINED__ +#ifndef _WIN32_WCE + static HIMAGELIST Read(LPSTREAM lpStream) + { + return ImageList_Read(lpStream); + } + + BOOL Write(LPSTREAM lpStream) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_Write(m_hImageList, lpStream); + } +#endif // !_WIN32_WCE + +#if (_WIN32_WINNT >= 0x0501) + static HRESULT ReadEx(DWORD dwFlags, LPSTREAM lpStream, REFIID riid, PVOID* ppv) + { + return ImageList_ReadEx(dwFlags, lpStream, riid, ppv); + } + + HRESULT WriteEx(DWORD dwFlags, LPSTREAM lpStream) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_WriteEx(m_hImageList, dwFlags, lpStream); + } +#endif // (_WIN32_WINNT >= 0x0501) +#endif // __IStream_INTERFACE_DEFINED__ + + // Drag operations + BOOL BeginDrag(int nImage, POINT ptHotSpot) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_BeginDrag(m_hImageList, nImage, ptHotSpot.x, ptHotSpot.y); + } + + BOOL BeginDrag(int nImage, int xHotSpot, int yHotSpot) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_BeginDrag(m_hImageList, nImage, xHotSpot, yHotSpot); + } + + static void EndDrag() + { + ImageList_EndDrag(); + } + + static BOOL DragMove(POINT pt) + { + return ImageList_DragMove(pt.x, pt.y); + } + + static BOOL DragMove(int x, int y) + { + return ImageList_DragMove(x, y); + } + + BOOL SetDragCursorImage(int nDrag, POINT ptHotSpot) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetDragCursorImage(m_hImageList, nDrag, ptHotSpot.x, ptHotSpot.y); + } + + BOOL SetDragCursorImage(int nDrag, int xHotSpot, int yHotSpot) + { + ATLASSERT(m_hImageList != NULL); + return ImageList_SetDragCursorImage(m_hImageList, nDrag, xHotSpot, yHotSpot); + } + + static BOOL DragShowNolock(BOOL bShow = TRUE) + { + return ImageList_DragShowNolock(bShow); + } + + static CImageList GetDragImage(LPPOINT lpPoint, LPPOINT lpPointHotSpot) + { + return CImageList(ImageList_GetDragImage(lpPoint, lpPointHotSpot)); + } + + static BOOL DragEnter(HWND hWnd, POINT point) + { + return ImageList_DragEnter(hWnd, point.x, point.y); + } + + static BOOL DragEnter(HWND hWnd, int x, int y) + { + return ImageList_DragEnter(hWnd, x, y); + } + + static BOOL DragLeave(HWND hWnd) + { + return ImageList_DragLeave(hWnd); + } + +#if (_WIN32_IE >= 0x0400) + CImageList Duplicate() const + { + ATLASSERT(m_hImageList != NULL); + return CImageList(ImageList_Duplicate(m_hImageList)); + } + + static CImageList Duplicate(HIMAGELIST hImageList) + { + ATLASSERT(hImageList != NULL); + return CImageList(ImageList_Duplicate(hImageList)); + } +#endif // (_WIN32_IE >= 0x0400) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CToolTipCtrl + +#ifndef _WIN32_WCE + +class CToolInfo : public TOOLINFO +{ +public: + CToolInfo(UINT nFlags, HWND hWnd, UINT nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL) + { + Init(nFlags, hWnd, nIDTool, lpRect, lpstrText, lUserParam); + } + + operator LPTOOLINFO() { return this; } + + operator LPARAM() { return (LPARAM)this; } + + void Init(UINT nFlags, HWND hWnd, UINT nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL) + { + ATLASSERT(::IsWindow(hWnd)); + memset(this, 0, sizeof(TOOLINFO)); + cbSize = TTTOOLINFO_V1_SIZE /*sizeof(TOOLINFO)*/; + uFlags = nFlags; + if(nIDTool == 0) + { + hwnd = ::GetParent(hWnd); + uFlags |= TTF_IDISHWND; + uId = (UINT_PTR)hWnd; + } + else + { + hwnd = hWnd; + uId = nIDTool; + } + if(lpRect != NULL) + rect = *lpRect; + hinst = ModuleHelper::GetResourceInstance(); + lpszText = lpstrText; + lParam = lUserParam; + } +}; + +template +class CToolTipCtrlT : public TBase +{ +public: +// Constructors + CToolTipCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CToolTipCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return TOOLTIPS_CLASS; + } + + void GetText(LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_GETTEXT, 0, (LPARAM)&lpToolInfo); + } + + void GetText(LPTSTR lpstrText, HWND hWnd, UINT nIDTool = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + CToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText); + ::SendMessage(m_hWnd, TTM_GETTEXT, 0, ti); + } + + BOOL GetToolInfo(LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, (LPARAM)lpToolInfo); + } + + BOOL GetToolInfo(HWND hWnd, UINT nIDTool, UINT* puFlags, LPRECT lpRect, LPTSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + ATLASSERT(puFlags != NULL); + ATLASSERT(lpRect != NULL); + CToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText); + BOOL bRet = (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, ti); + if(bRet != FALSE) + { + *puFlags = ti.uFlags; + *lpRect = ti.rect; + } + return bRet; + } + + void SetToolInfo(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETTOOLINFO, 0, (LPARAM)lpToolInfo); + } + + void SetToolRect(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, (LPARAM)lpToolInfo); + } + + void SetToolRect(HWND hWnd, UINT nIDTool, LPCRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + ATLASSERT(nIDTool != 0); + + CToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRect, NULL); + ::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, ti); + } + + int GetToolCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TTM_GETTOOLCOUNT, 0, 0L); + } + + int GetDelayTime(DWORD dwType) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TTM_GETDELAYTIME, dwType, 0L); + } + + void SetDelayTime(DWORD dwType, int nTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETDELAYTIME, dwType, MAKELPARAM(nTime, 0)); + } + + void GetMargin(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_GETMARGIN, 0, (LPARAM)lpRect); + } + + void SetMargin(LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETMARGIN, 0, (LPARAM)lpRect); + } + + int GetMaxTipWidth() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TTM_GETMAXTIPWIDTH, 0, 0L); + } + + int SetMaxTipWidth(int nWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TTM_SETMAXTIPWIDTH, 0, nWidth); + } + + COLORREF GetTipBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPBKCOLOR, 0, 0L); + } + + void SetTipBkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETTIPBKCOLOR, (WPARAM)clr, 0L); + } + + COLORREF GetTipTextColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPTEXTCOLOR, 0, 0L); + } + + void SetTipTextColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETTIPTEXTCOLOR, (WPARAM)clr, 0L); + } + + BOOL GetCurrentTool(LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_GETCURRENTTOOL, 0, (LPARAM)lpToolInfo); + } + +#if (_WIN32_IE >= 0x0500) + SIZE GetBubbleSize(LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TTM_GETBUBBLESIZE, 0, (LPARAM)lpToolInfo); + SIZE size = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) }; + return size; + } + + BOOL SetTitle(UINT uIcon, LPCTSTR lpstrTitle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_SETTITLE, uIcon, (LPARAM)lpstrTitle); + } +#endif // (_WIN32_IE >= 0x0500) + +#if (_WIN32_WINNT >= 0x0501) + void GetTitle(PTTGETTITLE pTTGetTitle) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_GETTITLE, 0, (LPARAM)pTTGetTitle); + } + + void SetWindowTheme(LPCWSTR lpstrTheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); + } +#endif // (_WIN32_WINNT >= 0x0501) + +// Operations + void Activate(BOOL bActivate) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_ACTIVATE, bActivate, 0L); + } + + BOOL AddTool(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, (LPARAM)lpToolInfo); + } + + BOOL AddTool(HWND hWnd, ATL::_U_STRINGorID text = LPSTR_TEXTCALLBACK, LPCRECT lpRectTool = NULL, UINT nIDTool = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + // the toolrect and toolid must both be zero or both valid + ATLASSERT((lpRectTool != NULL && nIDTool != 0) || (lpRectTool == NULL && nIDTool == 0)); + + CToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRectTool, (LPTSTR)text.m_lpstr); + return (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, ti); + } + + void DelTool(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_DELTOOL, 0, (LPARAM)lpToolInfo); + } + + void DelTool(HWND hWnd, UINT nIDTool = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + + CToolInfo ti(0, hWnd, nIDTool, NULL, NULL); + ::SendMessage(m_hWnd, TTM_DELTOOL, 0, ti); + } + + BOOL HitTest(LPTTHITTESTINFO lpHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)lpHitTestInfo); + } + + BOOL HitTest(HWND hWnd, POINT pt, LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + ATLASSERT(lpToolInfo != NULL); + + TTHITTESTINFO hti = { 0 }; + hti.ti.cbSize = TTTOOLINFO_V1_SIZE/*sizeof(TOOLINFO)*/; + hti.hwnd = hWnd; + hti.pt.x = pt.x; + hti.pt.y = pt.y; + if((BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)&hti) != FALSE) + { + *lpToolInfo = hti.ti; + return TRUE; + } + return FALSE; + } + + void RelayEvent(LPMSG lpMsg) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_RELAYEVENT, 0, (LPARAM)lpMsg); + } + + void UpdateTipText(LPTOOLINFO lpToolInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)lpToolInfo); + } + + void UpdateTipText(ATL::_U_STRINGorID text, HWND hWnd, UINT nIDTool = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hWnd != NULL); + + CToolInfo ti(0, hWnd, nIDTool, NULL, (LPTSTR)text.m_lpstr); + ::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, ti); + } + + BOOL EnumTools(UINT nTool, LPTOOLINFO lpToolInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_ENUMTOOLS, nTool, (LPARAM)lpToolInfo); + } + + void Pop() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_POP, 0, 0L); + } + + void TrackActivate(LPTOOLINFO lpToolInfo, BOOL bActivate) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_TRACKACTIVATE, bActivate, (LPARAM)lpToolInfo); + } + + void TrackPosition(int xPos, int yPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_TRACKPOSITION, 0, MAKELPARAM(xPos, yPos)); + } + +#if (_WIN32_IE >= 0x0400) + void Update() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_UPDATE, 0, 0L); + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + BOOL AdjustRect(LPRECT lpRect, BOOL bLarger /*= TRUE*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TTM_ADJUSTRECT, bLarger, (LPARAM)lpRect); + } +#endif // (_WIN32_IE >= 0x0500) + +#if (_WIN32_WINNT >= 0x0501) + void Popup() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TTM_POPUP, 0, 0L); + } +#endif // (_WIN32_WINNT >= 0x0501) +}; + +typedef CToolTipCtrlT CToolTipCtrl; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CHeaderCtrl + +template +class CHeaderCtrlT : public TBase +{ +public: +// Constructors + CHeaderCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CHeaderCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_HEADER; + } + + int GetItemCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_GETITEMCOUNT, 0, 0L); + } + + BOOL GetItem(int nIndex, LPHDITEM pHeaderItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETITEM, nIndex, (LPARAM)pHeaderItem); + } + + BOOL SetItem(int nIndex, LPHDITEM pHeaderItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_SETITEM, nIndex, (LPARAM)pHeaderItem); + } + + CImageList GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_GETIMAGELIST, 0, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_SETIMAGELIST, 0, (LPARAM)hImageList)); + } + + BOOL GetOrderArray(int nSize, int* lpnArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETORDERARRAY, nSize, (LPARAM)lpnArray); + } + + BOOL SetOrderArray(int nSize, int* lpnArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_SETORDERARRAY, nSize, (LPARAM)lpnArray); + } + + BOOL GetItemRect(int nIndex, LPRECT lpItemRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETITEMRECT, nIndex, (LPARAM)lpItemRect); + } + + int SetHotDivider(BOOL bPos, DWORD dwInputValue) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_SETHOTDIVIDER, bPos, dwInputValue); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int GetBitmapMargin() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_GETBITMAPMARGIN, 0, 0L); + } + + int SetBitmapMargin(int nWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_SETBITMAPMARGIN, nWidth, 0L); + } + + int SetFilterChangeTimeout(DWORD dwTimeOut) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_SETFILTERCHANGETIMEOUT, 0, dwTimeOut); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0600) + BOOL GetItemDropDownRect(int nIndex, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETITEMDROPDOWNRECT, nIndex, (LPARAM)lpRect); + } + + BOOL GetOverflowRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_GETOVERFLOWRECT, 0, (LPARAM)lpRect); + } + + int GetFocusedItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_GETFOCUSEDITEM, 0, 0L); + } + + BOOL SetFocusedItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_SETFOCUSEDITEM, 0, nIndex); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + int InsertItem(int nIndex, LPHDITEM phdi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_INSERTITEM, nIndex, (LPARAM)phdi); + } + + int AddItem(LPHDITEM phdi) + { + return InsertItem(GetItemCount(), phdi); + } + + BOOL DeleteItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_DELETEITEM, nIndex, 0L); + } + + BOOL Layout(HD_LAYOUT* pHeaderLayout) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, HDM_LAYOUT, 0, (LPARAM)pHeaderLayout); + } + + int HitTest(LPHDHITTESTINFO lpHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_HITTEST, 0, (LPARAM)lpHitTestInfo); + } + + int OrderToIndex(int nOrder) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_ORDERTOINDEX, nOrder, 0L); + } + + CImageList CreateDragImage(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_CREATEDRAGIMAGE, nIndex, 0L)); + } + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int EditFilter(int nColumn, BOOL bDiscardChanges) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_EDITFILTER, nColumn, MAKELPARAM(bDiscardChanges, 0)); + } + + int ClearFilter(int nColumn) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, nColumn, 0L); + } + + int ClearAllFilters() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, (WPARAM)-1, 0L); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +}; + +typedef CHeaderCtrlT CHeaderCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CListViewCtrl + +template +class CListViewCtrlT : public TBase +{ +public: +// Constructors + CListViewCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CListViewCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_LISTVIEW; + } + + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETBKCOLOR, 0, 0L); + } + + BOOL SetBkColor(COLORREF cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETBKCOLOR, 0, cr); + } + + CImageList GetImageList(int nImageListType) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_GETIMAGELIST, nImageListType, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList, int nImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, nImageList, (LPARAM)hImageList)); + } + + int GetItemCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETITEMCOUNT, 0, 0L); + } + + BOOL SetItemCount(int nItems) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, 0L); + } + + BOOL GetItem(LPLVITEM pItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(const LVITEM* pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem, + int nImage, UINT nState, UINT nStateMask, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.mask = nMask; + lvi.iItem = nItem; + lvi.iSubItem = nSubItem; + lvi.stateMask = nStateMask; + lvi.state = nState; + lvi.pszText = (LPTSTR) lpszItem; + lvi.iImage = nImage; + lvi.lParam = lParam; + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)&lvi); + } + + UINT GetItemState(int nItem, UINT nMask) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_GETITEMSTATE, nItem, nMask); + } + + BOOL SetItemState(int nItem, UINT nState, UINT nStateMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.state = nState; + lvi.stateMask = nStateMask; + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)&lvi); + } + + BOOL SetItemState(int nItem, LPLVITEM pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)pItem); + } + +#ifndef _ATL_NO_COM + BOOL GetItemText(int nItem, int nSubItem, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + LVITEM lvi = { 0 }; + lvi.iSubItem = nSubItem; + + LPTSTR lpstrText = NULL; + int nRes = 0; + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrText = new TCHAR[nLen]); + if(lpstrText == NULL) + break; + lpstrText[0] = NULL; + lvi.cchTextMax = nLen; + lvi.pszText = lpstrText; + nRes = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); + if(nRes < nLen - 1) + break; + delete [] lpstrText; + lpstrText = NULL; + } + + if(lpstrText != NULL) + { + if(nRes != 0) + bstrText = ::SysAllocString(T2OLE(lpstrText)); + delete [] lpstrText; + } + + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetItemText(int nItem, int nSubItem, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.iSubItem = nSubItem; + + strText.Empty(); + int nRes = 0; + for(int nLen = 256; ; nLen *= 2) + { + lvi.cchTextMax = nLen; + lvi.pszText = strText.GetBufferSetLength(nLen); + if(lvi.pszText == NULL) + { + nRes = 0; + break; + } + nRes = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); + if(nRes < nLen - 1) + break; + } + strText.ReleaseBuffer(); + return nRes; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + int GetItemText(int nItem, int nSubItem, LPTSTR lpszText, int nLen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.iSubItem = nSubItem; + lvi.cchTextMax = nLen; + lvi.pszText = lpszText; + return (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); + } + + BOOL SetItemText(int nItem, int nSubItem, LPCTSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(nItem, nSubItem, LVIF_TEXT, lpszText, 0, 0, 0, 0); + } + + DWORD_PTR GetItemData(int nItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.iItem = nItem; + lvi.mask = LVIF_PARAM; + BOOL bRet = (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)&lvi); + return (DWORD_PTR)(bRet ? lvi.lParam : NULL); + } + + BOOL SetItemData(int nItem, DWORD_PTR dwData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(nItem, 0, LVIF_PARAM, NULL, 0, 0, 0, (LPARAM)dwData); + } + + UINT GetCallbackMask() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_GETCALLBACKMASK, 0, 0L); + } + + BOOL SetCallbackMask(UINT nMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETCALLBACKMASK, nMask, 0L); + } + + BOOL GetItemPosition(int nItem, LPPOINT lpPoint) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMPOSITION, nItem, (LPARAM)lpPoint); + } + + BOOL SetItemPosition(int nItem, POINT pt) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt); + } + + BOOL SetItemPosition(int nItem, int x, int y) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON)); + POINT pt = { x, y }; + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt); + } + + int GetStringWidth(LPCTSTR lpsz) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETSTRINGWIDTH, 0, (LPARAM)lpsz); + } + + CEdit GetEditControl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, LVM_GETEDITCONTROL, 0, 0L)); + } + + BOOL GetColumn(int nCol, LVCOLUMN* pColumn) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMN, nCol, (LPARAM)pColumn); + } + + BOOL SetColumn(int nCol, const LVCOLUMN* pColumn) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMN, nCol, (LPARAM)pColumn); + } + + int GetColumnWidth(int nCol) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETCOLUMNWIDTH, nCol, 0L); + } + + BOOL SetColumnWidth(int nCol, int cx) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNWIDTH, nCol, MAKELPARAM(cx, 0)); + } + + BOOL GetViewRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETVIEWRECT, 0, (LPARAM)lpRect); + } + + COLORREF GetTextColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTCOLOR, 0, 0L); + } + + BOOL SetTextColor(COLORREF cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTCOLOR, 0, cr); + } + + COLORREF GetTextBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTBKCOLOR, 0, 0L); + } + + BOOL SetTextBkColor(COLORREF cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTBKCOLOR, 0, cr); + } + + int GetTopIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETTOPINDEX, 0, 0L); + } + + int GetCountPerPage() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETCOUNTPERPAGE, 0, 0L); + } + + BOOL GetOrigin(LPPOINT lpPoint) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETORIGIN, 0, (LPARAM)lpPoint); + } + + UINT GetSelectedCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_GETSELECTEDCOUNT, 0, 0L); + } + + BOOL GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const + { + ATLASSERT(::IsWindow(m_hWnd)); + lpRect->left = nCode; + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMRECT, (WPARAM)nItem, (LPARAM)lpRect); + } + +#ifndef _WIN32_WCE + HCURSOR GetHotCursor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HCURSOR)::SendMessage(m_hWnd, LVM_GETHOTCURSOR, 0, 0L); + } + + HCURSOR SetHotCursor(HCURSOR hHotCursor) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HCURSOR)::SendMessage(m_hWnd, LVM_SETHOTCURSOR, 0, (LPARAM)hHotCursor); + } + + int GetHotItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETHOTITEM, 0, 0L); + } + + int SetHotItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SETHOTITEM, nIndex, 0L); + } +#endif // !_WIN32_WCE + + BOOL GetColumnOrderArray(int nCount, int* lpnArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray); + } + + BOOL SetColumnOrderArray(int nCount, int* lpnArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray); + } + + CHeaderCtrl GetHeader() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CHeaderCtrl((HWND)::SendMessage(m_hWnd, LVM_GETHEADER, 0, 0L)); + } + + BOOL GetSubItemRect(int nItem, int nSubItem, int nFlag, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_REPORT); + ATLASSERT(lpRect != NULL); + lpRect->top = nSubItem; + lpRect->left = nFlag; + return (BOOL)::SendMessage(m_hWnd, LVM_GETSUBITEMRECT, nItem, (LPARAM)lpRect); + } + + DWORD SetIconSpacing(int cx, int cy) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_ICON); + return (DWORD)::SendMessage(m_hWnd, LVM_SETICONSPACING, 0, MAKELPARAM(cx, cy)); + } + + int GetISearchString(LPTSTR lpstr) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETISEARCHSTRING, 0, (LPARAM)lpstr); + } + + void GetItemSpacing(SIZE& sizeSpacing, BOOL bSmallIconView = FALSE) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, LVM_GETITEMSPACING, bSmallIconView, 0L); + sizeSpacing.cx = GET_X_LPARAM(dwRet); + sizeSpacing.cy = GET_Y_LPARAM(dwRet); + } + +#if (_WIN32_WCE >= 410) + void SetItemSpacing(INT cySpacing) + { + ATLASSERT(::IsWindow(m_hWnd)); + ListView_SetItemSpacing(m_hWnd, cySpacing); + } +#endif // (_WIN32_WCE >= 410) + + // single-selection only + int GetSelectedIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LVS_SINGLESEL) != 0); + return (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0)); + } + + BOOL GetSelectedItem(LPLVITEM pItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LVS_SINGLESEL) != 0); + ATLASSERT(pItem != NULL); + pItem->iItem = (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0)); + if(pItem->iItem == -1) + return FALSE; + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem); + } + + // extended list view styles + DWORD GetExtendedListViewStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0L); + } + + // dwExMask = 0 means all styles + DWORD SetExtendedListViewStyle(DWORD dwExStyle, DWORD dwExMask = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, dwExMask, dwExStyle); + } + + // checkboxes only + BOOL GetCheckState(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetExtendedListViewStyle() & LVS_EX_CHECKBOXES) != 0); + UINT uRet = GetItemState(nIndex, LVIS_STATEIMAGEMASK); + return (uRet >> 12) - 1; + } + + BOOL SetCheckState(int nItem, BOOL bCheck) + { + int nCheck = bCheck ? 2 : 1; // one based index + return SetItemState(nItem, INDEXTOSTATEIMAGEMASK(nCheck), LVIS_STATEIMAGEMASK); + } + + // view type + DWORD GetViewType() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (GetStyle() & LVS_TYPEMASK); + } + + DWORD SetViewType(DWORD dwType) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(dwType == LVS_ICON || dwType == LVS_SMALLICON || dwType == LVS_LIST || dwType == LVS_REPORT); + DWORD dwOldType = GetViewType(); + if(dwType != dwOldType) + ModifyStyle(LVS_TYPEMASK, (dwType & LVS_TYPEMASK)); + return dwOldType; + } + +#if (_WIN32_IE >= 0x0400) +#ifndef _WIN32_WCE + BOOL GetBkImage(LPLVBKIMAGE plvbki) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETBKIMAGE, 0, (LPARAM)plvbki); + } + + BOOL SetBkImage(LPLVBKIMAGE plvbki) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETBKIMAGE, 0, (LPARAM)plvbki); + } +#endif // !_WIN32_WCE + + int GetSelectionMark() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETSELECTIONMARK, 0, 0L); + } + + int SetSelectionMark(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SETSELECTIONMARK, 0, nIndex); + } + +#ifndef _WIN32_WCE + BOOL GetWorkAreas(int nWorkAreas, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETWORKAREAS, nWorkAreas, (LPARAM)lpRect); + } + + BOOL SetWorkAreas(int nWorkAreas, LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETWORKAREAS, nWorkAreas, (LPARAM)lpRect); + } + + DWORD GetHoverTime() const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0); + return (DWORD)::SendMessage(m_hWnd, LVM_GETHOVERTIME, 0, 0L); + } + + DWORD SetHoverTime(DWORD dwHoverTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0); + return (DWORD)::SendMessage(m_hWnd, LVM_SETHOVERTIME, 0, dwHoverTime); + } + + BOOL GetNumberOfWorkAreas(int* pnWorkAreas) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETNUMBEROFWORKAREAS, 0, (LPARAM)pnWorkAreas); + } +#endif // !_WIN32_WCE + + BOOL SetItemCountEx(int nItems, DWORD dwFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(((GetStyle() & LVS_OWNERDATA) != 0) && (((GetStyle() & LVS_TYPEMASK) == LVS_REPORT) || ((GetStyle() & LVS_TYPEMASK) == LVS_LIST))); + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, dwFlags); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_GETTOOLTIPS, 0, 0L)); + } + + CToolTipCtrl SetToolTips(HWND hWndTT) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L)); + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_WINNT >= 0x0501) + int GetSelectedColumn() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETSELECTEDCOLUMN, 0, 0L); + } + + void SetSelectedColumn(int nColumn) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_SETSELECTEDCOLUMN, nColumn, 0L); + } + + DWORD GetView() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, LVM_GETVIEW, 0, 0L); + } + + int SetView(DWORD dwView) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SETVIEW, dwView, 0L); + } + + BOOL IsGroupViewEnabled() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_ISGROUPVIEWENABLED, 0, 0L); + } + + int GetGroupInfo(int nGroupID, PLVGROUP pGroup) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETGROUPINFO, nGroupID, (LPARAM)pGroup); + } + + int SetGroupInfo(int nGroupID, PLVGROUP pGroup) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SETGROUPINFO, nGroupID, (LPARAM)pGroup); + } + + void GetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_GETGROUPMETRICS, 0, (LPARAM)pGroupMetrics); + } + + void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_SETGROUPMETRICS, 0, (LPARAM)pGroupMetrics); + } + + void GetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_GETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo); + } + + BOOL SetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo); + } + + void GetTileInfo(PLVTILEINFO pTileInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_GETTILEINFO, 0, (LPARAM)pTileInfo); + } + + BOOL SetTileInfo(PLVTILEINFO pTileInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETTILEINFO, 0, (LPARAM)pTileInfo); + } + + BOOL GetInsertMark(LPLVINSERTMARK pInsertMark) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETINSERTMARK, 0, (LPARAM)pInsertMark); + } + + BOOL SetInsertMark(LPLVINSERTMARK pInsertMark) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETINSERTMARK, 0, (LPARAM)pInsertMark); + } + + int GetInsertMarkRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETINSERTMARKRECT, 0, (LPARAM)lpRect); + } + + COLORREF GetInsertMarkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETINSERTMARKCOLOR, 0, 0L); + } + + COLORREF SetInsertMarkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_SETINSERTMARKCOLOR, 0, clr); + } + + COLORREF GetOutlineColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_GETOUTLINECOLOR, 0, 0L); + } + + COLORREF SetOutlineColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, LVM_SETOUTLINECOLOR, 0, clr); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + int GetGroupCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETGROUPCOUNT, 0, 0L); + } + + BOOL GetGroupInfoByIndex(int nIndex, PLVGROUP pGroup) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPINFOBYINDEX, nIndex, (LPARAM)pGroup); + } + + BOOL GetGroupRect(int nGroupID, int nType, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpRect != NULL); + if(lpRect != NULL) + lpRect->top = nType; + return (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPRECT, nGroupID, (LPARAM)lpRect); + } + + UINT GetGroupState(int nGroupID, UINT uMask) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_GETGROUPSTATE, nGroupID, (LPARAM)uMask); + } + + int GetFocusedGroup() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETFOCUSEDGROUP, 0, 0L); + } + + BOOL GetEmptyText(LPWSTR lpstrText, int cchText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETEMPTYTEXT, cchText, (LPARAM)lpstrText); + } + + BOOL GetFooterRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERRECT, 0, (LPARAM)lpRect); + } + + BOOL GetFooterInfo(LPLVFOOTERINFO lpFooterInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERINFO, 0, (LPARAM)lpFooterInfo); + } + + BOOL GetFooterItemRect(int nItem, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEMRECT, nItem, (LPARAM)lpRect); + } + + BOOL GetFooterItem(int nItem, LPLVFOOTERITEM lpFooterItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEM, nItem, (LPARAM)lpFooterItem); + } + + BOOL GetItemIndexRect(PLVITEMINDEX pItemIndex, int nSubItem, int nType, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pItemIndex != NULL); + ATLASSERT(lpRect != NULL); + if(lpRect != NULL) + { + lpRect->top = nSubItem; + lpRect->left = nType; + } + return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMINDEXRECT, (WPARAM)pItemIndex, (LPARAM)lpRect); + } + + BOOL SetItemIndexState(PLVITEMINDEX pItemIndex, UINT uState, UINT dwMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvi = { 0 }; + lvi.state = uState; + lvi.stateMask = dwMask; + return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMINDEXSTATE, (WPARAM)pItemIndex, (LPARAM)&lvi); + } + + BOOL GetNextItemIndex(PLVITEMINDEX pItemIndex, WORD wFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_GETNEXTITEMINDEX, (WPARAM)pItemIndex, MAKELPARAM(wFlags, 0)); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + int InsertColumn(int nCol, const LVCOLUMN* pColumn) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_INSERTCOLUMN, nCol, (LPARAM)pColumn); + } + + int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, + int nWidth = -1, int nSubItem = -1, int iImage = -1, int iOrder = -1) + { + LVCOLUMN column = { 0 }; + column.mask = LVCF_TEXT|LVCF_FMT; + column.pszText = (LPTSTR)lpszColumnHeading; + column.fmt = nFormat; + if (nWidth != -1) + { + column.mask |= LVCF_WIDTH; + column.cx = nWidth; + } + if (nSubItem != -1) + { + column.mask |= LVCF_SUBITEM; + column.iSubItem = nSubItem; + } + if (iImage != -1) + { + column.mask |= LVCF_IMAGE; + column.iImage = iImage; + } + if (iOrder != -1) + { + column.mask |= LVCF_ORDER; + column.iOrder = iOrder; + } + return InsertColumn(nCol, &column); + } + + BOOL DeleteColumn(int nCol) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_DELETECOLUMN, nCol, 0L); + } + + int InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask, int nImage, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM item = { 0 }; + item.mask = nMask; + item.iItem = nItem; + item.iSubItem = 0; + item.pszText = (LPTSTR)lpszItem; + item.state = nState; + item.stateMask = nStateMask; + item.iImage = nImage; + item.lParam = lParam; + return InsertItem(&item); + } + + int InsertItem(const LVITEM* pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_INSERTITEM, 0, (LPARAM)pItem); + } + + int InsertItem(int nItem, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(LVIF_TEXT, nItem, lpszItem, 0, 0, 0, 0); + } + + int InsertItem(int nItem, LPCTSTR lpszItem, int nImage) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(LVIF_TEXT|LVIF_IMAGE, nItem, lpszItem, 0, 0, nImage, 0); + } + + int GetNextItem(int nItem, int nFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, nItem, MAKELPARAM(nFlags, 0)); + } + + BOOL DeleteItem(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_DELETEITEM, nItem, 0L); + } + + BOOL DeleteAllItems() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_DELETEALLITEMS, 0, 0L); + } + + int FindItem(LVFINDINFO* pFindInfo, int nStart) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)pFindInfo); + } + + int HitTest(LVHITTESTINFO* pHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)pHitTestInfo); + } + + int HitTest(POINT pt, UINT* pFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVHITTESTINFO hti = { 0 }; + hti.pt = pt; + int nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)&hti); + if (pFlags != NULL) + *pFlags = hti.flags; + return nRes; + } + + BOOL EnsureVisible(int nItem, BOOL bPartialOK) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_ENSUREVISIBLE, nItem, MAKELPARAM(bPartialOK, 0)); + } + + BOOL Scroll(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SCROLL, size.cx, size.cy); + } + + BOOL RedrawItems(int nFirst, int nLast) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_REDRAWITEMS, nFirst, nLast); + } + + BOOL Arrange(UINT nCode) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_ARRANGE, nCode, 0L); + } + + CEdit EditLabel(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, LVM_EDITLABEL, nItem, 0L)); + } + + BOOL Update(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_UPDATE, nItem, 0L); + } + + BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMS, (WPARAM)lParamSort, (LPARAM)pfnCompare); + } + + CImageList RemoveImageList(int nImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, (WPARAM)nImageList, NULL)); + } + + CImageList CreateDragImage(int nItem, LPPOINT lpPoint) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_CREATEDRAGIMAGE, nItem, (LPARAM)lpPoint)); + } + + DWORD ApproximateViewRect(int cx = -1, int cy = -1, int nCount = -1) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, LVM_APPROXIMATEVIEWRECT, nCount, MAKELPARAM(cx, cy)); + } + + int SubItemHitTest(LPLVHITTESTINFO lpInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, 0, (LPARAM)lpInfo); + } + + int AddColumn(LPCTSTR strItem, int nItem, int nSubItem = -1, + int nMask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM, + int nFmt = LVCFMT_LEFT) + { + const int cxOffset = 15; + ATLASSERT(::IsWindow(m_hWnd)); + LVCOLUMN lvc = { 0 }; + lvc.mask = nMask; + lvc.fmt = nFmt; + lvc.pszText = (LPTSTR)strItem; + lvc.cx = GetStringWidth(lvc.pszText) + cxOffset; + if(nMask & LVCF_SUBITEM) + lvc.iSubItem = (nSubItem != -1) ? nSubItem : nItem; + return InsertColumn(nItem, &lvc); + } + + int AddItem(int nItem, int nSubItem, LPCTSTR strItem, int nImageIndex = -1) + { + ATLASSERT(::IsWindow(m_hWnd)); + LVITEM lvItem = { 0 }; + lvItem.mask = LVIF_TEXT; + lvItem.iItem = nItem; + lvItem.iSubItem = nSubItem; + lvItem.pszText = (LPTSTR)strItem; + if(nImageIndex != -1) + { + lvItem.mask |= LVIF_IMAGE; + lvItem.iImage = nImageIndex; + } + if(nSubItem == 0) + return InsertItem(&lvItem); + return SetItem(&lvItem) ? nItem : -1; + } + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMSEX, (WPARAM)lParamSort, (LPARAM)pfnCompare); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) + int InsertGroup(int nItem, PLVGROUP pGroup) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_INSERTGROUP, nItem, (LPARAM)pGroup); + } + + int AddGroup(PLVGROUP pGroup) + { + return InsertGroup(-1, pGroup); + } + + int RemoveGroup(int nGroupID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_REMOVEGROUP, nGroupID, 0L); + } + + void MoveGroup(int nGroupID, int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_MOVEGROUP, nGroupID, nItem); + } + + void MoveItemToGroup(int nItem, int nGroupID) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_MOVEITEMTOGROUP, nItem, nGroupID); + } + + int EnableGroupView(BOOL bEnable) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_ENABLEGROUPVIEW, bEnable, 0L); + } + + int SortGroups(PFNLVGROUPCOMPARE pCompareFunc, LPVOID lpVoid = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SORTGROUPS, (WPARAM)pCompareFunc, (LPARAM)lpVoid); + } + + void InsertGroupSorted(PLVINSERTGROUPSORTED pInsertGroupSorted) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_INSERTGROUPSORTED, (WPARAM)pInsertGroupSorted, 0L); + } + + void RemoveAllGroups() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_REMOVEALLGROUPS, 0, 0L); + } + + BOOL HasGroup(int nGroupID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_HASGROUP, nGroupID, 0L); + } + + BOOL InsertMarkHitTest(LPPOINT lpPoint, LPLVINSERTMARK pInsertMark) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)pInsertMark); + } + + BOOL SetInfoTip(PLVSETINFOTIP pSetInfoTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LVM_SETINFOTIP, 0, (LPARAM)pSetInfoTip); + } + + void CancelEditLabel() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, LVM_CANCELEDITLABEL, 0, 0L); + } + + UINT MapIndexToID(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, LVM_MAPINDEXTOID, nIndex, 0L); + } + + int MapIDToIndex(UINT uID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_MAPIDTOINDEX, uID, 0L); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + int HitTestEx(LPLVHITTESTINFO lpHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo); + } + + int HitTestEx(POINT pt, UINT* pFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + LVHITTESTINFO hti = { 0 }; + hti.pt = pt; + int nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)&hti); + if (pFlags != NULL) + *pFlags = hti.flags; + return nRes; + } + + int SubItemHitTestEx(LPLVHITTESTINFO lpHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo); + } +#endif // (_WIN32_WINNT >= 0x0600) + + // single-selection only + BOOL SelectItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & LVS_SINGLESEL) != 0); + + BOOL bRet = SetItemState(nIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); + if(bRet) + bRet = EnsureVisible(nIndex, FALSE); + return bRet; + } +}; + +typedef CListViewCtrlT CListViewCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CTreeViewCtrl + +template +class CTreeViewCtrlT : public TBase +{ +public: +// Constructors + CTreeViewCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTreeViewCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_TREEVIEW; + } + + UINT GetCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TVM_GETCOUNT, 0, 0L); + } + + UINT GetIndent() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TVM_GETINDENT, 0, 0L); + } + + void SetIndent(UINT nIndent) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TVM_SETINDENT, nIndent, 0L); + } + + CImageList GetImageList(int nImageListType = TVSIL_NORMAL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_GETIMAGELIST, (WPARAM)nImageListType, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList, int nImageListType = TVSIL_NORMAL) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageListType, (LPARAM)hImageList)); + } + + BOOL GetItem(LPTVITEM pItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(LPTVITEM pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR lpszItem, int nImage, + int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = nMask; + item.pszText = (LPTSTR) lpszItem; + item.iImage = nImage; + item.iSelectedImage = nSelectedImage; + item.state = nState; + item.stateMask = nStateMask; + item.lParam = lParam; + return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)&item); + } + + BOOL GetItemText(HTREEITEM hItem, LPTSTR lpstrText, int nLen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpstrText != NULL); + + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_TEXT; + item.pszText = lpstrText; + item.cchTextMax = nLen; + + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + } + +#ifndef _ATL_NO_COM + BOOL GetItemText(HTREEITEM hItem, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_TEXT; + + LPTSTR lpstrText = NULL; + BOOL bRet = FALSE; + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrText = new TCHAR[nLen]); + if(lpstrText == NULL) + break; + lpstrText[0] = NULL; + item.pszText = lpstrText; + item.cchTextMax = nLen; + bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + if(!bRet || (lstrlen(item.pszText) < nLen - 1)) + break; + delete [] lpstrText; + lpstrText = NULL; + } + + if(lpstrText != NULL) + { + if(bRet) + bstrText = ::SysAllocString(T2OLE(lpstrText)); + delete [] lpstrText; + } + + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL GetItemText(HTREEITEM hItem, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_TEXT; + + strText.Empty(); + BOOL bRet = FALSE; + for(int nLen = 256; ; nLen *= 2) + { + item.pszText = strText.GetBufferSetLength(nLen); + if(item.pszText == NULL) + { + bRet = FALSE; + break; + } + item.cchTextMax = nLen; + bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + if(!bRet || (lstrlen(item.pszText) < nLen - 1)) + break; + } + strText.ReleaseBuffer(); + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL SetItemText(HTREEITEM hItem, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(hItem, TVIF_TEXT, lpszItem, 0, 0, 0, 0, NULL); + } + + BOOL GetItemImage(HTREEITEM hItem, int& nImage, int& nSelectedImage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE; + BOOL bRes = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + if (bRes) + { + nImage = item.iImage; + nSelectedImage = item.iSelectedImage; + } + return bRes; + } + + BOOL SetItemImage(HTREEITEM hItem, int nImage, int nSelectedImage) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(hItem, TVIF_IMAGE|TVIF_SELECTEDIMAGE, NULL, nImage, nSelectedImage, 0, 0, NULL); + } + + UINT GetItemState(HTREEITEM hItem, UINT nStateMask) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + return (((UINT)::SendMessage(m_hWnd, TVM_GETITEMSTATE, (WPARAM)hItem, (LPARAM)nStateMask)) & nStateMask); +#else // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)) + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_STATE; + item.state = 0; + item.stateMask = nStateMask; + ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + return (item.state & nStateMask); +#endif // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)) + } + + BOOL SetItemState(HTREEITEM hItem, UINT nState, UINT nStateMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(hItem, TVIF_STATE, NULL, 0, 0, nState, nStateMask, NULL); + } + + DWORD_PTR GetItemData(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_PARAM; + BOOL bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + return (DWORD_PTR)(bRet ? item.lParam : NULL); + } + + BOOL SetItemData(HTREEITEM hItem, DWORD_PTR dwData) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(hItem, TVIF_PARAM, NULL, 0, 0, 0, 0, (LPARAM)dwData); + } + + CEdit GetEditControl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, TVM_GETEDITCONTROL, 0, 0L)); + } + + UINT GetVisibleCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TVM_GETVISIBLECOUNT, 0, 0L); + } + + BOOL GetItemRect(HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly) const + { + ATLASSERT(::IsWindow(m_hWnd)); + *(HTREEITEM*)lpRect = hItem; + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEMRECT, (WPARAM)bTextOnly, (LPARAM)lpRect); + } + + BOOL ItemHasChildren(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVITEM item = { 0 }; + item.hItem = hItem; + item.mask = TVIF_CHILDREN; + ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); + return item.cChildren; + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_GETTOOLTIPS, 0, 0L)); + } + + CToolTipCtrl SetToolTips(HWND hWndTT) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L)); + } +#endif // !_WIN32_WCE + + int GetISearchString(LPTSTR lpstr) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_GETISEARCHSTRING, 0, (LPARAM)lpstr); + } + + // checkboxes only + BOOL GetCheckState(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & TVS_CHECKBOXES) != 0); + UINT uRet = GetItemState(hItem, TVIS_STATEIMAGEMASK); + return (uRet >> 12) - 1; + } + + BOOL SetCheckState(HTREEITEM hItem, BOOL bCheck) + { + int nCheck = bCheck ? 2 : 1; // one based index + return SetItemState(hItem, INDEXTOSTATEIMAGEMASK(nCheck), TVIS_STATEIMAGEMASK); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_GETBKCOLOR, 0, 0L); + } + + COLORREF SetBkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_SETBKCOLOR, 0, (LPARAM)clr); + } + + COLORREF GetInsertMarkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_GETINSERTMARKCOLOR, 0, 0L); + } + + COLORREF SetInsertMarkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_SETINSERTMARKCOLOR, 0, (LPARAM)clr); + } + + int GetItemHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_GETITEMHEIGHT, 0, 0L); + } + + int SetItemHeight(int cyHeight) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_SETITEMHEIGHT, cyHeight, 0L); + } + + int GetScrollTime() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_GETSCROLLTIME, 0, 0L); + } + + int SetScrollTime(int nScrollTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TVM_SETSCROLLTIME, nScrollTime, 0L); + } + + COLORREF GetTextColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_GETTEXTCOLOR, 0, 0L); + } + + COLORREF SetTextColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_SETTEXTCOLOR, 0, (LPARAM)clr); + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + COLORREF GetLineColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_GETLINECOLOR, 0, 0L); + } + + COLORREF SetLineColor(COLORREF clrNew /*= CLR_DEFAULT*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TVM_SETLINECOLOR, 0, (LPARAM)clrNew); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetItem(LPTVITEMEX pItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem); + } + + BOOL SetItem(LPTVITEMEX pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + + DWORD GetExtendedStyle() const + { +#ifndef TVM_GETEXTENDEDSTYLE + const UINT TVM_GETEXTENDEDSTYLE = (TV_FIRST + 45); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TVM_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask) + { +#ifndef TVM_SETEXTENDEDSTYLE + const UINT TVM_SETEXTENDEDSTYLE = (TV_FIRST + 44); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TVM_SETEXTENDEDSTYLE, dwMask, dwStyle); + } + +#if (_WIN32_WINNT >= 0x0600) + BOOL SetAutoScrollInfo(UINT uPixPerSec, UINT uUpdateTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETAUTOSCROLLINFO, (WPARAM)uPixPerSec, (LPARAM)uUpdateTime); + } + + DWORD GetSelectedCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TVM_GETSELECTEDCOUNT, 0, 0L); + } + + BOOL GetItemPartRect(HTREEITEM hItem, TVITEMPART partID, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVGETITEMPARTRECTINFO gipri = { hItem, lpRect, partID }; + return (BOOL)::SendMessage(m_hWnd, TVM_GETITEMPARTRECT, 0, (LPARAM)&gipri); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + HTREEITEM InsertItem(LPTVINSERTSTRUCT lpInsertStruct) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct); + } + + HTREEITEM InsertItem(LPCTSTR lpszItem, int nImage, + int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter); + } + + HTREEITEM InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter); + } + + HTREEITEM InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, + int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam, + HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + TVINSERTSTRUCT tvis = { 0 }; + tvis.hParent = hParent; + tvis.hInsertAfter = hInsertAfter; + tvis.item.mask = nMask; + tvis.item.pszText = (LPTSTR) lpszItem; + tvis.item.iImage = nImage; + tvis.item.iSelectedImage = nSelectedImage; + tvis.item.state = nState; + tvis.item.stateMask = nStateMask; + tvis.item.lParam = lParam; + return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis); + } + + BOOL DeleteItem(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)hItem); + } + + BOOL DeleteAllItems() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); + } + + BOOL Expand(HTREEITEM hItem, UINT nCode = TVE_EXPAND) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_EXPAND, nCode, (LPARAM)hItem); + } + + HTREEITEM GetNextItem(HTREEITEM hItem, UINT nCode) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem); + } + + HTREEITEM GetChildItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + } + + HTREEITEM GetNextSiblingItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + } + + HTREEITEM GetPrevSiblingItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem); + } + + HTREEITEM GetParentItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); + } + + HTREEITEM GetFirstVisibleItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L); + } + + HTREEITEM GetNextVisibleItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem); + } + + HTREEITEM GetPrevVisibleItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem); + } + + HTREEITEM GetSelectedItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L); + } + + HTREEITEM GetDropHilightItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L); + } + + HTREEITEM GetRootItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L); + } + +#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + HTREEITEM GetLastVisibleItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L); + } +#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0600) + HTREEITEM GetNextSelectedItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L); + } +#endif // (_WIN32_IE >= 0x0600) + + BOOL Select(HTREEITEM hItem, UINT nCode) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, nCode, (LPARAM)hItem); + } + + BOOL SelectItem(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem); + } + + BOOL SelectDropTarget(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItem); + } + + BOOL SelectSetFirstVisible(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_FIRSTVISIBLE, (LPARAM)hItem); + } + + CEdit EditLabel(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, TVM_EDITLABEL, 0, (LPARAM)hItem)); + } + + BOOL EndEditLabelNow(BOOL bCancel) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_ENDEDITLABELNOW, bCancel, 0L); + } + + HTREEITEM HitTest(TVHITTESTINFO* pHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo); + } + + HTREEITEM HitTest(POINT pt, UINT* pFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVHITTESTINFO hti = { 0 }; + hti.pt = pt; + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti); + if (pFlags != NULL) + *pFlags = hti.flags; + return hTreeItem; + } + + BOOL SortChildren(HTREEITEM hItem, BOOL bRecurse = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDREN, (WPARAM)bRecurse, (LPARAM)hItem); + } + + BOOL EnsureVisible(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem); + } + + BOOL SortChildrenCB(LPTVSORTCB pSort, BOOL bRecurse = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDRENCB, (WPARAM)bRecurse, (LPARAM)pSort); + } + + CImageList RemoveImageList(int nImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageList, NULL)); + } + + CImageList CreateDragImage(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItem)); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL SetInsertMark(HTREEITEM hTreeItem, BOOL bAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, bAfter, (LPARAM)hTreeItem); + } + + BOOL RemoveInsertMark() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, 0, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) + HTREEITEM MapAccIDToHTREEITEM(UINT uID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L); + } + + UINT MapHTREEITEMToAccID(HTREEITEM hTreeItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TVM_MAPHTREEITEMTOACCID, (WPARAM)hTreeItem, 0L); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + void ShowInfoTip(HTREEITEM hItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TVM_SHOWINFOTIP, 0, (LPARAM)hItem); + } +#endif // (_WIN32_WINNT >= 0x0600) +}; + +typedef CTreeViewCtrlT CTreeViewCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CTreeViewCtrlEx + +// forward declaration +template class CTreeViewCtrlExT; + +// Note: TBase here is for CTreeViewCtrlExT, and not for CTreeItemT itself +template +class CTreeItemT +{ +public: + HTREEITEM m_hTreeItem; + CTreeViewCtrlExT* m_pTreeView; + +// Construction + CTreeItemT(HTREEITEM hTreeItem = NULL, CTreeViewCtrlExT* pTreeView = NULL) : m_hTreeItem(hTreeItem), m_pTreeView(pTreeView) + { } + + CTreeItemT(const CTreeItemT& posSrc) + { + *this = posSrc; + } + + operator HTREEITEM() { return m_hTreeItem; } + + CTreeItemT& operator =(const CTreeItemT& itemSrc) + { + m_hTreeItem = itemSrc.m_hTreeItem; + m_pTreeView = itemSrc.m_pTreeView; + return *this; + } + +// Attributes + CTreeViewCtrlExT* GetTreeView() const { return m_pTreeView; } + + BOOL operator !() const { return m_hTreeItem == NULL; } + + BOOL IsNull() const { return m_hTreeItem == NULL; } + + BOOL GetRect(LPRECT lpRect, BOOL bTextOnly) const; + BOOL GetText(LPTSTR lpstrText, int nLen) const; +#ifndef _ATL_NO_COM + BOOL GetText(BSTR& bstrText) const; +#endif // !_ATL_NO_COM +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL GetText(_CSTRING_NS::CString& strText) const; +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL SetText(LPCTSTR lpszItem); + BOOL GetImage(int& nImage, int& nSelectedImage) const; + BOOL SetImage(int nImage, int nSelectedImage); + UINT GetState(UINT nStateMask) const; + BOOL SetState(UINT nState, UINT nStateMask); + DWORD_PTR GetData() const; + BOOL SetData(DWORD_PTR dwData); + BOOL SetItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam); + +// Operations + CTreeItemT InsertAfter(LPCTSTR lpstrItem, HTREEITEM hItemAfter, int nImageIndex) + { + return _Insert(lpstrItem, nImageIndex, hItemAfter); + } + + CTreeItemT AddHead(LPCTSTR lpstrItem, int nImageIndex) + { + return _Insert(lpstrItem, nImageIndex, TVI_FIRST); + } + + CTreeItemT AddTail(LPCTSTR lpstrItem, int nImageIndex) + { + return _Insert(lpstrItem, nImageIndex, TVI_LAST); + } + + CTreeItemT GetChild() const; + CTreeItemT GetNext(UINT nCode) const; + CTreeItemT GetNextSibling() const; + CTreeItemT GetPrevSibling() const; + CTreeItemT GetParent() const; + CTreeItemT GetFirstVisible() const; + CTreeItemT GetNextVisible() const; + CTreeItemT GetPrevVisible() const; + CTreeItemT GetSelected() const; + CTreeItemT GetDropHilight() const; + CTreeItemT GetRoot() const; +#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + CTreeItemT GetLastVisible() const; +#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0600) + CTreeItemT GetNextSelected() const; +#endif // (_WIN32_IE >= 0x0600) + BOOL HasChildren() const; + BOOL Delete(); + BOOL Expand(UINT nCode = TVE_EXPAND); + BOOL Select(UINT nCode); + BOOL Select(); + BOOL SelectDropTarget(); + BOOL SelectSetFirstVisible(); + HWND EditLabel(); + HIMAGELIST CreateDragImage(); + BOOL SortChildren(BOOL bRecurse = FALSE); + BOOL EnsureVisible(); + CTreeItemT _Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter); + int GetImageIndex() const; +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL SetInsertMark(BOOL bAfter); +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) +#if (_WIN32_WINNT >= 0x0501) + UINT MapHTREEITEMToAccID() const; +#endif // (_WIN32_WINNT >= 0x0501) +#if (_WIN32_WINNT >= 0x0600) + void ShowInfoTip(); + BOOL GetPartRect(TVITEMPART partID, LPRECT lpRect) const; +#endif // (_WIN32_WINNT >= 0x0600) +}; + +typedef CTreeItemT CTreeItem; + + +template +class CTreeViewCtrlExT : public CTreeViewCtrlT< TBase > +{ +public: +// Constructors + CTreeViewCtrlExT(HWND hWnd = NULL) : CTreeViewCtrlT< TBase >(hWnd) + { } + + CTreeViewCtrlExT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Operations (overides that return CTreeItem) + CTreeItemT InsertItem(LPTVINSERTSTRUCT lpInsertStruct) + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct); + return CTreeItemT(hTreeItem, this); + } + + CTreeItemT InsertItem(LPCTSTR lpszItem, int nImage, + int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter); + } + + CTreeItemT InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + return InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter); + } + + CTreeItemT GetNextItem(HTREEITEM hItem, UINT nCode) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetChildItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetNextSiblingItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetPrevSiblingItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetParentItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetFirstVisibleItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetNextVisibleItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetPrevVisibleItem(HTREEITEM hItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetSelectedItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetDropHilightItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT GetRootItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + +#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + CTreeItemT GetLastVisibleItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } +#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0600) + CTreeItemT GetNextSelectedItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } +#endif // (_WIN32_IE >= 0x0600) + + CTreeItemT HitTest(TVHITTESTINFO* pHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + + CTreeItemT InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, + int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam, + HTREEITEM hParent, HTREEITEM hInsertAfter) + { + ATLASSERT(::IsWindow(m_hWnd)); + TVINSERTSTRUCT tvis = { 0 }; + tvis.hParent = hParent; + tvis.hInsertAfter = hInsertAfter; + tvis.item.mask = nMask; + tvis.item.pszText = (LPTSTR) lpszItem; + tvis.item.iImage = nImage; + tvis.item.iSelectedImage = nSelectedImage; + tvis.item.state = nState; + tvis.item.stateMask = nStateMask; + tvis.item.lParam = lParam; + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis); + return CTreeItemT(hTreeItem, this); + } + + CTreeItemT HitTest(POINT pt, UINT* pFlags) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TVHITTESTINFO hti = { 0 }; + hti.pt = pt; + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti); + if (pFlags != NULL) + *pFlags = hti.flags; + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } + +#if (_WIN32_WINNT >= 0x0501) + CTreeItemT MapAccIDToHTREEITEM(UINT uID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L); + return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); + } +#endif // (_WIN32_WINNT >= 0x0501) +}; + +typedef CTreeViewCtrlExT CTreeViewCtrlEx; + + +// CTreeItem inline methods +template +inline BOOL CTreeItemT::GetRect(LPRECT lpRect, BOOL bTextOnly) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemRect(m_hTreeItem,lpRect,bTextOnly); +} + +template +inline CTreeItemT CTreeItemT::GetNext(UINT nCode) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetNextItem(m_hTreeItem,nCode); +} + +template +inline CTreeItemT CTreeItemT::GetChild() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetChildItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetNextSibling() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetNextSiblingItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetPrevSibling() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetPrevSiblingItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetParent() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetParentItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetFirstVisible() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetFirstVisibleItem(); +} + +template +inline CTreeItemT CTreeItemT::GetNextVisible() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetNextVisibleItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetPrevVisible() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetPrevVisibleItem(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::GetSelected() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetSelectedItem(); +} + +template +inline CTreeItemT CTreeItemT::GetDropHilight() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetDropHilightItem(); +} + +template +inline CTreeItemT CTreeItemT::GetRoot() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetRootItem(); +} + +#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) +template +inline CTreeItemT CTreeItemT::GetLastVisible() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetLastVisibleItem(); +} +#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0600) +template +inline CTreeItemT CTreeItemT::GetNextSelected() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetNextSelectedItem(); +} +#endif // (_WIN32_IE >= 0x0600) + +template +inline BOOL CTreeItemT::GetText(LPTSTR lpstrText, int nLen) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemText(m_hTreeItem, lpstrText, nLen); +} + +#ifndef _ATL_NO_COM +#ifdef _OLEAUTO_H_ +template +inline BOOL CTreeItemT::GetText(BSTR& bstrText) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemText(m_hTreeItem, bstrText); +} +#endif // _OLEAUTO_H_ +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) +template +inline BOOL CTreeItemT::GetText(_CSTRING_NS::CString& strText) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemText(m_hTreeItem, strText); +} +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +template +inline BOOL CTreeItemT::GetImage(int& nImage, int& nSelectedImage) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemImage(m_hTreeItem,nImage,nSelectedImage); +} + +template +inline UINT CTreeItemT::GetState(UINT nStateMask) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemState(m_hTreeItem,nStateMask); +} + +template +inline DWORD_PTR CTreeItemT::GetData() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemData(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::SetItem(UINT nMask, LPCTSTR lpszItem, int nImage, + int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItem(m_hTreeItem, nMask, lpszItem, nImage, nSelectedImage, nState, nStateMask, lParam); +} + +template +inline BOOL CTreeItemT::SetText(LPCTSTR lpszItem) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItemText(m_hTreeItem,lpszItem); +} + +template +inline BOOL CTreeItemT::SetImage(int nImage, int nSelectedImage) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItemImage(m_hTreeItem,nImage,nSelectedImage); +} + +template +inline BOOL CTreeItemT::SetState(UINT nState, UINT nStateMask) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItemState(m_hTreeItem,nState,nStateMask); +} + +template +inline BOOL CTreeItemT::SetData(DWORD_PTR dwData) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetItemData(m_hTreeItem,dwData); +} + +template +inline BOOL CTreeItemT::HasChildren() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->ItemHasChildren(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::Delete() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->DeleteItem(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::Expand(UINT nCode /*= TVE_EXPAND*/) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->Expand(m_hTreeItem,nCode); +} + +template +inline BOOL CTreeItemT::Select(UINT nCode) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->Select(m_hTreeItem,nCode); +} + +template +inline BOOL CTreeItemT::Select() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SelectItem(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::SelectDropTarget() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SelectDropTarget(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::SelectSetFirstVisible() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SelectSetFirstVisible(m_hTreeItem); +} + +template +inline HWND CTreeItemT::EditLabel() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->EditLabel(m_hTreeItem); +} + +template +inline HIMAGELIST CTreeItemT::CreateDragImage() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->CreateDragImage(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::SortChildren(BOOL bRecurse /*= FALSE*/) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SortChildren(m_hTreeItem, bRecurse); +} + +template +inline BOOL CTreeItemT::EnsureVisible() +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->EnsureVisible(m_hTreeItem); +} + +template +inline CTreeItemT CTreeItemT::_Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter) +{ + ATLASSERT(m_pTreeView != NULL); + TVINSERTSTRUCT ins = { 0 }; + ins.hParent = m_hTreeItem; + ins.hInsertAfter = hItemAfter; + ins.item.mask = TVIF_TEXT; + ins.item.pszText = (LPTSTR)lpstrItem; + if(nImageIndex != -1) + { + ins.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; + ins.item.iImage = nImageIndex; + ins.item.iSelectedImage = nImageIndex; + } + return CTreeItemT(m_pTreeView->InsertItem(&ins), m_pTreeView); +} + +template +inline int CTreeItemT::GetImageIndex() const +{ + ATLASSERT(m_pTreeView != NULL); + TVITEM item = { 0 }; + item.mask = TVIF_HANDLE | TVIF_IMAGE; + item.hItem = m_hTreeItem; + m_pTreeView->GetItem(&item); + return item.iImage; +} + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) +template +inline BOOL CTreeItemT::SetInsertMark(BOOL bAfter) +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->SetInsertMark(m_hTreeItem, bAfter); +} +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) +template +inline UINT CTreeItemT::MapHTREEITEMToAccID() const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->MapHTREEITEMToAccID(m_hTreeItem); +} +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) +template +inline void CTreeItemT::ShowInfoTip() +{ + ATLASSERT(m_pTreeView != NULL); + m_pTreeView->ShowInfoTip(m_hTreeItem); +} + +template +inline BOOL CTreeItemT::GetPartRect(TVITEMPART partID, LPRECT lpRect) const +{ + ATLASSERT(m_pTreeView != NULL); + return m_pTreeView->GetItemPartRect(m_hTreeItem, partID, lpRect); +} +#endif // (_WIN32_WINNT >= 0x0600) + + +/////////////////////////////////////////////////////////////////////////////// +// CToolBarCtrl + +template +class CToolBarCtrlT : public TBase +{ +public: +// Construction + CToolBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CToolBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return TOOLBARCLASSNAME; + } + + BOOL IsButtonEnabled(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONENABLED, nID, 0L); + } + + BOOL IsButtonChecked(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONCHECKED, nID, 0L); + } + + BOOL IsButtonPressed(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONPRESSED, nID, 0L); + } + + BOOL IsButtonHidden(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return(BOOL) ::SendMessage(m_hWnd, TB_ISBUTTONHIDDEN, nID, 0L); + } + + BOOL IsButtonIndeterminate(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONINDETERMINATE, nID, 0L); + } + + int GetState(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETSTATE, nID, 0L); + } + + BOOL SetState(int nID, UINT nState) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETSTATE, nID, MAKELPARAM(nState, 0)); + } + + BOOL GetButton(int nIndex, LPTBBUTTON lpButton) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETBUTTON, nIndex, (LPARAM)lpButton); + } + + int GetButtonCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_BUTTONCOUNT, 0, 0L); + } + + BOOL GetItemRect(int nIndex, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETITEMRECT, nIndex, (LPARAM)lpRect); + } + + void SetButtonStructSize(int nSize = sizeof(TBBUTTON)) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_BUTTONSTRUCTSIZE, nSize, 0L); + } + + BOOL SetButtonSize(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(size.cx, size.cy)); + } + + BOOL SetButtonSize(int cx, int cy) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cy)); + } + + BOOL SetBitmapSize(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(size.cx, size.cy)); + } + + BOOL SetBitmapSize(int cx, int cy) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(cx, cy)); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TB_GETTOOLTIPS, 0, 0L)); + } + + void SetToolTips(HWND hWndToolTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L); + } +#endif // !_WIN32_WCE + + void SetNotifyWnd(HWND hWnd) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETPARENT, (WPARAM)hWnd, 0L); + } + + int GetRows() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETROWS, 0, 0L); + } + + void SetRows(int nRows, BOOL bLarger, LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETROWS, MAKELPARAM(nRows, bLarger), (LPARAM)lpRect); + } + + BOOL SetCmdID(int nIndex, UINT nID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETCMDID, nIndex, nID); + } + + DWORD GetBitmapFlags() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_GETBITMAPFLAGS, 0, 0L); + } + + int GetBitmap(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETBITMAP, nID, 0L); + } + + int GetButtonText(int nID, LPTSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETBUTTONTEXT, nID, (LPARAM)lpstrText); + } + + // nIndex - IE5 or higher only + CImageList GetImageList(int nIndex = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETIMAGELIST, nIndex, 0L)); + } + + // nIndex - IE5 or higher only + CImageList SetImageList(HIMAGELIST hImageList, int nIndex = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETIMAGELIST, nIndex, (LPARAM)hImageList)); + } + + // nIndex - IE5 or higher only + CImageList GetDisabledImageList(int nIndex = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETDISABLEDIMAGELIST, nIndex, 0L)); + } + + // nIndex - IE5 or higher only + CImageList SetDisabledImageList(HIMAGELIST hImageList, int nIndex = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETDISABLEDIMAGELIST, nIndex, (LPARAM)hImageList)); + } + +#ifndef _WIN32_WCE + // nIndex - IE5 or higher only + CImageList GetHotImageList(int nIndex = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETHOTIMAGELIST, nIndex, 0L)); + } + + // nIndex - IE5 or higher only + CImageList SetHotImageList(HIMAGELIST hImageList, int nIndex = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETHOTIMAGELIST, nIndex, (LPARAM)hImageList)); + } +#endif // !_WIN32_WCE + + DWORD GetStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_GETSTYLE, 0, 0L); + } + + void SetStyle(DWORD dwStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETSTYLE, 0, dwStyle); + } + + DWORD GetButtonSize() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L); + } + + void GetButtonSize(SIZE& size) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L); + size.cx = LOWORD(dwRet); + size.cy = HIWORD(dwRet); + } + + BOOL GetRect(int nID, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETRECT, nID, (LPARAM)lpRect); + } + + int GetTextRows() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETTEXTROWS, 0, 0L); + } + + BOOL SetButtonWidth(int cxMin, int cxMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cxMin, cxMax)); + } + + BOOL SetIndent(int nIndent) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETINDENT, nIndent, 0L); + } + + BOOL SetMaxTextRows(int nMaxTextRows) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, nMaxTextRows, 0L); + } + +#if (_WIN32_IE >= 0x0400) +#ifndef _WIN32_WCE + BOOL GetAnchorHighlight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETANCHORHIGHLIGHT, 0, 0L); + } + + BOOL SetAnchorHighlight(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETANCHORHIGHLIGHT, bEnable, 0L); + } +#endif // !_WIN32_WCE + + int GetButtonInfo(int nID, LPTBBUTTONINFO lptbbi) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETBUTTONINFO, nID, (LPARAM)lptbbi); + } + + BOOL SetButtonInfo(int nID, LPTBBUTTONINFO lptbbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)lptbbi); + } + + BOOL SetButtonInfo(int nID, DWORD dwMask, BYTE Style, BYTE State, LPCTSTR lpszItem, + int iImage, WORD cx, int iCommand, DWORD_PTR lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBBUTTONINFO tbbi = { 0 }; + tbbi.cbSize = sizeof(TBBUTTONINFO); + tbbi.dwMask = dwMask; + tbbi.idCommand = iCommand; + tbbi.iImage = iImage; + tbbi.fsState = State; + tbbi.fsStyle = Style; + tbbi.cx = cx; + tbbi.pszText = (LPTSTR) lpszItem; + tbbi.lParam = lParam; + return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)&tbbi); + } + +#ifndef _WIN32_WCE + int GetHotItem() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETHOTITEM, 0, 0L); + } + + int SetHotItem(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_SETHOTITEM, nItem, 0L); + } +#endif // !_WIN32_WCE + + BOOL IsButtonHighlighted(int nButtonID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONHIGHLIGHTED, nButtonID, 0L); + } + + DWORD SetDrawTextFlags(DWORD dwMask, DWORD dwFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_SETDRAWTEXTFLAGS, dwMask, dwFlags); + } + +#ifndef _WIN32_WCE + BOOL GetColorScheme(LPCOLORSCHEME lpcs) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETCOLORSCHEME, 0, (LPARAM)lpcs); + } + + void SetColorScheme(LPCOLORSCHEME lpcs) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETCOLORSCHEME, 0, (LPARAM)lpcs); + } + + DWORD GetExtendedStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, dwStyle); + } + + void GetInsertMark(LPTBINSERTMARK lptbim) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_GETINSERTMARK, 0, (LPARAM)lptbim); + } + + void SetInsertMark(LPTBINSERTMARK lptbim) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETINSERTMARK, 0, (LPARAM)lptbim); + } + + COLORREF GetInsertMarkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TB_GETINSERTMARKCOLOR, 0, 0L); + } + + COLORREF SetInsertMarkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, TB_SETINSERTMARKCOLOR, 0, (LPARAM)clr); + } + + BOOL GetMaxSize(LPSIZE lpSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETMAXSIZE, 0, (LPARAM)lpSize); + } + + void GetPadding(LPSIZE lpSizePadding) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpSizePadding != NULL); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETPADDING, 0, 0L); + lpSizePadding->cx = GET_X_LPARAM(dwRet); + lpSizePadding->cy = GET_Y_LPARAM(dwRet); + } + + void SetPadding(int cx, int cy, LPSIZE lpSizePadding = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_SETPADDING, 0, MAKELPARAM(cx, cy)); + if(lpSizePadding != NULL) + { + lpSizePadding->cx = GET_X_LPARAM(dwRet); + lpSizePadding->cy = GET_Y_LPARAM(dwRet); + } + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int GetString(int nString, LPTSTR lpstrString, int cchMaxLen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(cchMaxLen, nString), (LPARAM)lpstrString); + } + + int GetStringBSTR(int nString, BSTR& bstrString) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrString == NULL); + int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL)); + if(nLength != -1) + { + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(nLength + 1); + if(lpstrText != NULL) + { + nLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstrText); + if(nLength != -1) + bstrString = ::SysAllocString(T2OLE(lpstrText)); + } + else + { + nLength = -1; + } + } + + return nLength; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetString(int nString, _CSTRING_NS::CString& str) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL)); + if(nLength != -1) + { + LPTSTR lpstr = str.GetBufferSetLength(nLength + 1); + if(lpstr != NULL) + nLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstr); + else + nLength = -1; + str.ReleaseBuffer(); + } + return nLength; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) + void GetMetrics(LPTBMETRICS lptbm) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_GETMETRICS, 0, (LPARAM)lptbm); + } + + void SetMetrics(LPTBMETRICS lptbm) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETMETRICS, 0, (LPARAM)lptbm); + } + + void SetWindowTheme(LPCWSTR lpstrTheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_WINNT >= 0x0600) + CImageList GetPressedImageList(int nIndex = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETPRESSEDIMAGELIST, nIndex, 0L)); + } + + CImageList SetPressedImageList(HIMAGELIST hImageList, int nIndex = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETPRESSEDIMAGELIST, nIndex, (LPARAM)hImageList)); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + BOOL EnableButton(int nID, BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ENABLEBUTTON, nID, MAKELPARAM(bEnable, 0)); + } + + BOOL CheckButton(int nID, BOOL bCheck = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_CHECKBUTTON, nID, MAKELPARAM(bCheck, 0)); + } + + BOOL PressButton(int nID, BOOL bPress = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_PRESSBUTTON, nID, MAKELPARAM(bPress, 0)); + } + + BOOL HideButton(int nID, BOOL bHide = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_HIDEBUTTON, nID, MAKELPARAM(bHide, 0)); + } + + BOOL Indeterminate(int nID, BOOL bIndeterminate = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_INDETERMINATE, nID, MAKELPARAM(bIndeterminate, 0)); + } + + int AddBitmap(int nNumButtons, UINT nBitmapID) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBADDBITMAP tbab = { 0 }; + tbab.hInst = ModuleHelper::GetResourceInstance(); + ATLASSERT(tbab.hInst != NULL); + tbab.nID = nBitmapID; + return (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab); + } + + int AddBitmap(int nNumButtons, HBITMAP hBitmap) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBADDBITMAP tbab = { 0 }; + tbab.hInst = NULL; + tbab.nID = (UINT_PTR)hBitmap; + return (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab); + } + + BOOL AddButtons(int nNumButtons, LPTBBUTTON lpButtons) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_ADDBUTTONS, nNumButtons, (LPARAM)lpButtons); + } + + BOOL InsertButton(int nIndex, LPTBBUTTON lpButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)lpButton); + } + + BOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap, + INT_PTR iString, DWORD_PTR lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBBUTTON tbb = { 0 }; + tbb.fsStyle = Style; + tbb.fsState = State; + tbb.idCommand = iCommand; + tbb.iBitmap = iBitmap; + tbb.iString = iString; + tbb.dwData = lParam; + return (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)&tbb); + } + + BOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap, + LPCTSTR lpszItem, DWORD_PTR lParam) + { + return InsertButton(nIndex, iCommand, Style, State, iBitmap, (INT_PTR)lpszItem, lParam); + } + + BOOL AddButton(LPTBBUTTON lpButton) + { + return InsertButton(-1, lpButton); + } + + BOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, INT_PTR iString, DWORD_PTR lParam) + { + return InsertButton(-1, iCommand, Style, State, iBitmap, iString, lParam); + } + + BOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, LPCTSTR lpszItem, DWORD_PTR lParam) + { + return InsertButton(-1, iCommand, Style, State, iBitmap, lpszItem, lParam); + } + + BOOL DeleteButton(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_DELETEBUTTON, nIndex, 0L); + } + + UINT CommandToIndex(UINT nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TB_COMMANDTOINDEX, nID, 0L); + } + +#ifndef _WIN32_WCE + void SaveState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBSAVEPARAMS tbs = { 0 }; + tbs.hkr = hKeyRoot; + tbs.pszSubKey = lpszSubKey; + tbs.pszValueName = lpszValueName; + ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)TRUE, (LPARAM)&tbs); + } + + void RestoreState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName) + { + ATLASSERT(::IsWindow(m_hWnd)); + TBSAVEPARAMS tbs = { 0 }; + tbs.hkr = hKeyRoot; + tbs.pszSubKey = lpszSubKey; + tbs.pszValueName = lpszValueName; + ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)FALSE, (LPARAM)&tbs); + } + + void Customize() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_CUSTOMIZE, 0, 0L); + } +#endif // !_WIN32_WCE + + int AddString(UINT nStringID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_ADDSTRING, (WPARAM)ModuleHelper::GetResourceInstance(), (LPARAM)nStringID); + } + + int AddStrings(LPCTSTR lpszStrings) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_ADDSTRING, 0, (LPARAM)lpszStrings); + } + + void AutoSize() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TB_AUTOSIZE, 0, 0L); + } + + BOOL ChangeBitmap(int nID, int nBitmap) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_CHANGEBITMAP, nID, MAKELPARAM(nBitmap, 0)); + } + + int LoadImages(int nBitmapID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)ModuleHelper::GetResourceInstance()); + } + + int LoadStdImages(int nBitmapID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)HINST_COMMCTRL); + } + + BOOL ReplaceBitmap(LPTBREPLACEBITMAP ptbrb) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_REPLACEBITMAP, 0, (LPARAM)ptbrb); + } + +#if (_WIN32_IE >= 0x0400) + int HitTest(LPPOINT lpPoint) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TB_HITTEST, 0, (LPARAM)lpPoint); + } + +#ifndef _WIN32_WCE + BOOL InsertMarkHitTest(LPPOINT lpPoint, LPTBINSERTMARK lptbim) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)lptbim); + } + + BOOL InsertMarkHitTest(int x, int y, LPTBINSERTMARK lptbim) const + { + ATLASSERT(::IsWindow(m_hWnd)); + POINT pt = { x, y }; + return (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)&pt, (LPARAM)lptbim); + } + + BOOL MapAccelerator(TCHAR chAccel, int& nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_MAPACCELERATOR, (WPARAM)chAccel, (LPARAM)&nID); + } + + BOOL MarkButton(int nID, BOOL bHighlight = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_MARKBUTTON, nID, MAKELPARAM(bHighlight, 0)); + } + + BOOL MoveButton(int nOldPos, int nNewPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TB_MOVEBUTTON, nOldPos, nNewPos); + } + + HRESULT GetObject(REFIID iid, LPVOID* ppvObject) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, TB_GETOBJECT, (WPARAM)&iid, (LPARAM)ppvObject); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) +}; + +typedef CToolBarCtrlT CToolBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CStatusBarCtrl + +template +class CStatusBarCtrlT : public TBase +{ +public: +// Constructors + CStatusBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CStatusBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Methods + static LPCTSTR GetWndClassName() + { + return STATUSCLASSNAME; + } + + int GetParts(int nParts, int* pParts) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, SB_GETPARTS, nParts, (LPARAM)pParts); + } + + BOOL SetParts(int nParts, int* pWidths) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_SETPARTS, nParts, (LPARAM)pWidths); + } + + int GetTextLength(int nPane, int* pType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L); + if (pType != NULL) + *pType = (int)(short)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + + int GetText(int nPane, LPTSTR lpszText, int* pType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXT, (WPARAM)nPane, (LPARAM)lpszText); + if(pType != NULL) + *pType = (int)(short)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + +#ifndef _ATL_NO_COM + BOOL GetTextBSTR(int nPane, BSTR& bstrText, int* pType = NULL) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + ATLASSERT(bstrText == NULL); + int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L)); + if(nLength == 0) + return FALSE; + + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(nLength + 1); + if(lpstrText == NULL) + return FALSE; + + if(!GetText(nPane, lpstrText, pType)) + return FALSE; + + bstrText = ::SysAllocString(T2OLE(lpstrText)); + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetText(int nPane, _CSTRING_NS::CString& strText, int* pType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L)); + if(nLength == 0) + return 0; + + LPTSTR lpstr = strText.GetBufferSetLength(nLength); + if(lpstr == NULL) + return 0; + return GetText(nPane, lpstr, pType); + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL SetText(int nPane, LPCTSTR lpszText, int nType = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + return (BOOL)::SendMessage(m_hWnd, SB_SETTEXT, (nPane | nType), (LPARAM)lpszText); + } + + BOOL GetRect(int nPane, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + return (BOOL)::SendMessage(m_hWnd, SB_GETRECT, nPane, (LPARAM)lpRect); + } + + BOOL GetBorders(int* pBorders) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)pBorders); + } + + BOOL GetBorders(int& nHorz, int& nVert, int& nSpacing) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int borders[3] = { 0, 0, 0 }; + BOOL bResult = (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)&borders); + if(bResult) + { + nHorz = borders[0]; + nVert = borders[1]; + nSpacing = borders[2]; + } + return bResult; + } + + void SetMinHeight(int nMin) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, SB_SETMINHEIGHT, nMin, 0L); + } + + BOOL SetSimple(BOOL bSimple = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_SIMPLE, bSimple, 0L); + } + + BOOL IsSimple() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_ISSIMPLE, 0, 0L); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, SB_SETUNICODEFORMAT, bUnicode, 0L); + } + + void GetTipText(int nPane, LPTSTR lpstrText, int nSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + ::SendMessage(m_hWnd, SB_GETTIPTEXT, MAKEWPARAM(nPane, nSize), (LPARAM)lpstrText); + } + + void SetTipText(int nPane, LPCTSTR lpstrText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + ::SendMessage(m_hWnd, SB_SETTIPTEXT, nPane, (LPARAM)lpstrText); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) + COLORREF SetBkColor(COLORREF clrBk) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, SB_SETBKCOLOR, 0, (LPARAM)clrBk); + } + + HICON GetIcon(int nPane) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + return (HICON)::SendMessage(m_hWnd, SB_GETICON, nPane, 0L); + } + + BOOL SetIcon(int nPane, HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPane < 256); + return (BOOL)::SendMessage(m_hWnd, SB_SETICON, nPane, (LPARAM)hIcon); + } +#endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) +}; + +typedef CStatusBarCtrlT CStatusBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CTabCtrl + +template +class CTabCtrlT : public TBase +{ +public: +// Constructors + CTabCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTabCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_TABCONTROL; + } + + CImageList GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_GETIMAGELIST, 0, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_SETIMAGELIST, 0, (LPARAM)hImageList)); + } + + int GetItemCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_GETITEMCOUNT, 0, 0L); + } + + BOOL GetItem(int nItem, LPTCITEM pTabCtrlItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_GETITEM, nItem, (LPARAM)pTabCtrlItem); + } + + BOOL SetItem(int nItem, LPTCITEM pTabCtrlItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)pTabCtrlItem); + } + + int SetItem(int nItem, UINT mask, LPCTSTR lpszItem, DWORD dwState, DWORD dwStateMask, int iImage, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TCITEM tci = { 0 }; + tci.mask = mask; + tci.pszText = (LPTSTR) lpszItem; + tci.dwState = dwState; + tci.dwStateMask = dwStateMask; + tci.iImage = iImage; + tci.lParam = lParam; + return (int)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)&tci); + } + + BOOL GetItemRect(int nItem, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_GETITEMRECT, nItem, (LPARAM)lpRect); + } + + int GetCurSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_GETCURSEL, 0, 0L); + } + + int SetCurSel(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_SETCURSEL, nItem, 0L); + } + + SIZE SetItemSize(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwSize = (DWORD)::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(size.cx, size.cy)); + SIZE sizeRet = { GET_X_LPARAM(dwSize), GET_Y_LPARAM(dwSize) }; + return sizeRet; + } + + void SetItemSize(int cx, int cy) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(cx, cy)); + } + + void SetPadding(SIZE size) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_SETPADDING, 0, MAKELPARAM(size.cx, size.cy)); + } + + int GetRowCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_GETROWCOUNT, 0, 0L); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetTooltips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TCM_GETTOOLTIPS, 0, 0L)); + } + + void SetTooltips(HWND hWndToolTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L); + } +#endif // !_WIN32_WCE + + int GetCurFocus() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_GETCURFOCUS, 0, 0L); + } + + void SetCurFocus(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_SETCURFOCUS, nItem, 0L); + } + + BOOL SetItemExtra(int cbExtra) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetItemCount() == 0); // must be empty + return (BOOL)::SendMessage(m_hWnd, TCM_SETITEMEXTRA, cbExtra, 0L); + } + + int SetMinTabWidth(int nWidth = -1) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_SETMINTABWIDTH, 0, nWidth); + } + +#if (_WIN32_IE >= 0x0400) + DWORD GetExtendedStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TCM_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, TCM_SETEXTENDEDSTYLE, dwExMask, dwExStyle); + } + +#ifndef _WIN32_WCE + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +// Operations + int InsertItem(int nItem, LPTCITEM pTabCtrlItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)pTabCtrlItem); + } + + int InsertItem(int nItem, UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + TCITEM tci = { 0 }; + tci.mask = mask; + tci.pszText = (LPTSTR) lpszItem; + tci.iImage = iImage; + tci.lParam = lParam; + return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci); + } + + int InsertItem(int nItem, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + TCITEM tci = { 0 }; + tci.mask = TCIF_TEXT; + tci.pszText = (LPTSTR) lpszItem; + return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci); + } + + int AddItem(LPTCITEM pTabCtrlItem) + { + return InsertItem(GetItemCount(), pTabCtrlItem); + } + + int AddItem(UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam) + { + return InsertItem(GetItemCount(), mask, lpszItem, iImage, lParam); + } + + int AddItem(LPCTSTR lpszItem) + { + return InsertItem(GetItemCount(), lpszItem); + } + + BOOL DeleteItem(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_DELETEITEM, nItem, 0L); + } + + BOOL DeleteAllItems() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_DELETEALLITEMS, 0, 0L); + } + + void AdjustRect(BOOL bLarger, LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_ADJUSTRECT, bLarger, (LPARAM)lpRect); + } + + void RemoveImage(int nImage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_REMOVEIMAGE, nImage, 0L); + } + + int HitTest(TC_HITTESTINFO* pHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TCM_HITTEST, 0, (LPARAM)pHitTestInfo); + } + + void DeselectAll(BOOL bExcludeFocus = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TCM_DESELECTALL, bExcludeFocus, 0L); + } + +#if (_WIN32_IE >= 0x0400) + BOOL HighlightItem(int nIndex, BOOL bHighlight = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TCM_HIGHLIGHTITEM, nIndex, MAKELPARAM(bHighlight, 0)); + } +#endif // (_WIN32_IE >= 0x0400) +}; + +typedef CTabCtrlT CTabCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CTrackBarCtrl + +template +class CTrackBarCtrlT : public TBase +{ +public: +// Constructors + CTrackBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTrackBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return TRACKBAR_CLASS; + } + + int GetLineSize() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETLINESIZE, 0, 0L); + } + + int SetLineSize(int nSize) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_SETLINESIZE, 0, nSize); + } + + int GetPageSize() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETPAGESIZE, 0, 0L); + } + + int SetPageSize(int nSize) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_SETPAGESIZE, 0, nSize); + } + + int GetRangeMin() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETRANGEMIN, 0, 0L); + } + + void SetRangeMin(int nMin, BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETRANGEMIN, bRedraw, nMin); + } + + int GetRangeMax() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETRANGEMAX, 0, 0L); + } + + void SetRangeMax(int nMax, BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETRANGEMAX, bRedraw, nMax); + } + + void GetRange(int& nMin, int& nMax) const + { + nMin = GetRangeMin(); + nMax = GetRangeMax(); + } + + void SetRange(int nMin, int nMax, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETRANGE, bRedraw, MAKELPARAM(nMin, nMax)); + } + + int GetSelStart() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETSELSTART, 0, 0L); + } + + void SetSelStart(int nMin) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETSELSTART, 0, (LPARAM)nMin); + } + + int GetSelEnd() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETSELEND, 0, 0L); + } + + void SetSelEnd(int nMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETSELEND, 0, (LPARAM)nMax); + } + + void GetSelection(int& nMin, int& nMax) const + { + nMin = GetSelStart(); + nMax = GetSelEnd(); + } + + void SetSelection(int nMin, int nMax) + { + SetSelStart(nMin); + SetSelEnd(nMax); + } + + void GetChannelRect(LPRECT lprc) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_GETCHANNELRECT, 0, (LPARAM)lprc); + } + + void GetThumbRect(LPRECT lprc) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)lprc); + } + + int GetPos() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETPOS, 0, 0L); + } + + void SetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETPOS, TRUE, nPos); + } + + UINT GetNumTics() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, TBM_GETNUMTICS, 0, 0L); + } + + DWORD* GetTicArray() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD*)::SendMessage(m_hWnd, TBM_GETPTICS, 0, 0L); + } + + int GetTic(int nTic) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETTIC, nTic, 0L); + } + + BOOL SetTic(int nTic) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TBM_SETTIC, 0, nTic); + } + + int GetTicPos(int nTic) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETTICPOS, nTic, 0L); + } + + void SetTicFreq(int nFreq) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETTICFREQ, nFreq, 0L); + } + + int GetThumbLength() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_GETTHUMBLENGTH, 0, 0L); + } + + void SetThumbLength(int nLength) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETTHUMBLENGTH, nLength, 0L); + } + + void SetSel(int nStart, int nEnd, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & TBS_ENABLESELRANGE) != 0); + ::SendMessage(m_hWnd, TBM_SETSEL, bRedraw, MAKELPARAM(nStart, nEnd)); + } + + ATL::CWindow GetBuddy(BOOL bLeft = TRUE) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_GETBUDDY, bLeft, 0L)); + } + + ATL::CWindow SetBuddy(HWND hWndBuddy, BOOL bLeft = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_SETBUDDY, bLeft, (LPARAM)hWndBuddy)); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TBM_GETTOOLTIPS, 0, 0L)); + } + + void SetToolTips(HWND hWndTT) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETTOOLTIPS, (WPARAM)hWndTT, 0L); + } + + int SetTipSide(int nSide) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, TBM_SETTIPSIDE, nSide, 0L); + } +#endif // !_WIN32_WCE + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TBM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, TBM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +// Operations + void ClearSel(BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_CLEARSEL, bRedraw, 0L); + } + + void VerifyPos() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_SETPOS, FALSE, 0L); + } + + void ClearTics(BOOL bRedraw = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, TBM_CLEARTICS, bRedraw, 0L); + } +}; + +typedef CTrackBarCtrlT CTrackBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CUpDownCtrl + +template +class CUpDownCtrlT : public TBase +{ +public: +// Constructors + CUpDownCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CUpDownCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return UPDOWN_CLASS; + } + + UINT GetAccel(int nAccel, UDACCEL* pAccel) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETACCEL, nAccel, (LPARAM)pAccel)); + } + + BOOL SetAccel(int nAccel, UDACCEL* pAccel) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)LOWORD(::SendMessage(m_hWnd, UDM_SETACCEL, nAccel, (LPARAM)pAccel)); + } + + UINT GetBase() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETBASE, 0, 0L)); + } + + int SetBase(int nBase) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, UDM_SETBASE, nBase, 0L); + } + + ATL::CWindow GetBuddy() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_GETBUDDY, 0, 0L)); + } + + ATL::CWindow SetBuddy(HWND hWndBuddy) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_SETBUDDY, (WPARAM)hWndBuddy, 0L)); + } + + int GetPos(LPBOOL lpbError = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETPOS, 0, 0L); + // Note: Seems that Windows always sets error to TRUE if + // UDS_SETBUDDYINT style is not used + if(lpbError != NULL) + *lpbError = (HIWORD(dwRet) != 0) ? TRUE : FALSE; + return (int)(short)LOWORD(dwRet); + } + + int SetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, UDM_SETPOS, 0, MAKELPARAM(nPos, 0))); + } + + DWORD GetRange() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L); + } + + void GetRange(int& nLower, int& nUpper) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L); + nLower = (int)(short)HIWORD(dwRet); + nUpper = (int)(short)LOWORD(dwRet); + } + + void SetRange(int nLower, int nUpper) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, UDM_SETRANGE, 0, MAKELPARAM(nUpper, nLower)); + } + +#if (_WIN32_IE >= 0x0400) + void SetRange32(int nLower, int nUpper) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, UDM_SETRANGE32, nLower, nUpper); + } + + void GetRange32(int& nLower, int& nUpper) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, UDM_GETRANGE32, (WPARAM)&nLower, (LPARAM)&nUpper); + } + +#ifndef _WIN32_WCE + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, UDM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, UDM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int GetPos32(LPBOOL lpbError = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + // Note: Seems that Windows always sets error to TRUE if + // UDS_SETBUDDYINT style is not used + return (int)::SendMessage(m_hWnd, UDM_GETPOS32, 0, (LPARAM)lpbError); + } + + int SetPos32(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, UDM_SETPOS32, 0, (LPARAM)nPos); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +}; + +typedef CUpDownCtrlT CUpDownCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CProgressBarCtrl + +template +class CProgressBarCtrlT : public TBase +{ +public: +// Constructors + CProgressBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CProgressBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return PROGRESS_CLASS; + } + + DWORD SetRange(int nLower, int nUpper) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE, 0, MAKELPARAM(nLower, nUpper)); + } + + int SetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETPOS, nPos, 0L)); + } + + int OffsetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_DELTAPOS, nPos, 0L)); + } + + int SetStep(int nStep) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETSTEP, nStep, 0L)); + } + + UINT GetPos() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, PBM_GETPOS, 0, 0L); + } + + void GetRange(PPBRANGE pPBRange) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pPBRange != NULL); + ::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)pPBRange); + } + + void GetRange(int& nLower, int& nUpper) const + { + ATLASSERT(::IsWindow(m_hWnd)); + PBRANGE range = { 0 }; + ::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)&range); + nLower = range.iLow; + nUpper = range.iHigh; + } + + int GetRangeLimit(BOOL bLowLimit) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PBM_GETRANGE, bLowLimit, (LPARAM)NULL); + } + + DWORD SetRange32(int nMin, int nMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE32, nMin, nMax); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + COLORREF SetBarColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PBM_SETBARCOLOR, 0, (LPARAM)clr); + } + + COLORREF SetBkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PBM_SETBKCOLOR, 0, (LPARAM)clr); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE) + BOOL SetMarquee(BOOL bMarquee, UINT uUpdateTime = 0U) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PBM_SETMARQUEE, (WPARAM)bMarquee, (LPARAM)uUpdateTime); + } +#endif // (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE) + +#if (_WIN32_WINNT >= 0x0600) + int GetStep() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PBM_GETSTEP, 0, 0L); + } + + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PBM_GETBKCOLOR, 0, 0L); + } + + COLORREF GetBarColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PBM_GETBARCOLOR, 0, 0L); + } + + int GetState() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PBM_GETSTATE, 0, 0L); + } + + int SetState(int nState) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PBM_SETSTATE, nState, 0L); + } +#endif // (_WIN32_WINNT >= 0x0600) + +// Operations + int StepIt() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_STEPIT, 0, 0L)); + } +}; + +typedef CProgressBarCtrlT CProgressBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CHotKeyCtrl + +#ifndef _WIN32_WCE + +template +class CHotKeyCtrlT : public TBase +{ +public: +// Constructors + CHotKeyCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CHotKeyCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return HOTKEY_CLASS; + } + + DWORD GetHotKey() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L); + } + + void GetHotKey(WORD &wVirtualKeyCode, WORD &wModifiers) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dw = (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L); + wVirtualKeyCode = LOBYTE(LOWORD(dw)); + wModifiers = HIBYTE(LOWORD(dw)); + } + + void SetHotKey(WORD wVirtualKeyCode, WORD wModifiers) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, HKM_SETHOTKEY, MAKEWORD(wVirtualKeyCode, wModifiers), 0L); + } + + void SetRules(WORD wInvalidComb, WORD wModifiers) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, HKM_SETRULES, wInvalidComb, MAKELPARAM(wModifiers, 0)); + } +}; + +typedef CHotKeyCtrlT CHotKeyCtrl; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CAnimateCtrl + +#ifndef _WIN32_WCE + +template +class CAnimateCtrlT : public TBase +{ +public: +// Constructors + CAnimateCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CAnimateCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return ANIMATE_CLASS; + } + +// Operations + BOOL Open(ATL::_U_STRINGorID FileName) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, (LPARAM)FileName.m_lpstr); + } + + BOOL Play(UINT nFrom, UINT nTo, UINT nRep) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_PLAY, nRep, MAKELPARAM(nFrom, nTo)); + } + + BOOL Stop() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_STOP, 0, 0L); + } + + BOOL Close() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, 0L); + } + + BOOL Seek(UINT nTo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_PLAY, 0, MAKELPARAM(nTo, nTo)); + } + + // Vista only + BOOL IsPlaying() const + { +#ifndef ACM_ISPLAYING + const UINT ACM_ISPLAYING = (WM_USER+104); +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, ACM_ISPLAYING, 0, 0L); + } +}; + +typedef CAnimateCtrlT CAnimateCtrl; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CRichEditCtrl + +#ifndef _WIN32_WCE + +#ifdef _UNICODE +#if (_RICHEDIT_VER == 0x0100) +#undef RICHEDIT_CLASS +#define RICHEDIT_CLASS L"RICHEDIT" +#endif // (_RICHEDIT_VER == 0x0100) +#endif // _UNICODE + +template +class CRichEditCtrlT : public TBase +{ +public: +// Constructors + CRichEditCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CRichEditCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return RICHEDIT_CLASS; + } + + static LPCTSTR GetLibraryName() + { +#if (_RICHEDIT_VER >= 0x0200) + return _T("RICHED20.DLL"); +#else + return _T("RICHED32.DLL"); +#endif + } + + int GetLineCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L); + } + + BOOL GetModify() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L); + } + + void SetModify(BOOL bModified = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L); + } + + void GetRect(LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect); + } + + DWORD GetOptions() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETOPTIONS, 0, 0L); + } + + DWORD SetOptions(WORD wOperation, DWORD dwOptions) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_SETOPTIONS, wOperation, dwOptions); + } + + // NOTE: first word in lpszBuffer must contain the size of the buffer! + int GetLine(int nIndex, LPTSTR lpszBuffer) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); + } + + int GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + *(LPWORD)lpszBuffer = (WORD)nMaxLength; + return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); + } + + BOOL CanUndo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L); + } + + BOOL CanPaste(UINT nFormat = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, nFormat, 0L); + } + + void GetSel(LONG& nStartChar, LONG& nEndChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + CHARRANGE cr = { 0, 0 }; + ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); + nStartChar = cr.cpMin; + nEndChar = cr.cpMax; + } + + void GetSel(CHARRANGE &cr) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); + } + + int SetSel(LONG nStartChar, LONG nEndChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + CHARRANGE cr = { nStartChar, nEndChar }; + return (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr); + } + + int SetSel(CHARRANGE &cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr); + } + + int SetSelAll() + { + return SetSel(0, -1); + } + + int SetSelNone() + { + return SetSel(-1, 0); + } + + DWORD GetDefaultCharFormat(CHARFORMAT& cf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf); + } + + DWORD GetSelectionCharFormat(CHARFORMAT& cf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf); + } + + DWORD GetEventMask() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETEVENTMASK, 0, 0L); + } + + LONG GetLimitText() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L); + } + + DWORD GetParaFormat(PARAFORMAT& pf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + pf.cbSize = sizeof(PARAFORMAT); + return (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf); + } + +#if (_RICHEDIT_VER >= 0x0200) + LONG GetSelText(LPTSTR lpstrBuff) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff); + } +#else // !(_RICHEDIT_VER >= 0x0200) + // RichEdit 1.0 EM_GETSELTEXT is ANSI only + LONG GetSelText(LPSTR lpstrBuff) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff); + } +#endif // !(_RICHEDIT_VER >= 0x0200) + +#ifndef _ATL_NO_COM + BOOL GetSelTextBSTR(BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + + CHARRANGE cr = { 0, 0 }; + ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); + +#if (_RICHEDIT_VER >= 0x0200) + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1); + if(lpstrText == NULL) + return FALSE; + if(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0) + return FALSE; + + bstrText = ::SysAllocString(T2W(lpstrText)); +#else // !(_RICHEDIT_VER >= 0x0200) + CTempBuffer buff; + LPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1); + if(lpstrText == NULL) + return FALSE; + if(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0) + return FALSE; + + bstrText = ::SysAllocString(A2W(lpstrText)); +#endif // !(_RICHEDIT_VER >= 0x0200) + + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + LONG GetSelText(_CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + + CHARRANGE cr = { 0, 0 }; + ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); + +#if (_RICHEDIT_VER >= 0x0200) + LONG lLen = 0; + LPTSTR lpstrText = strText.GetBufferSetLength(cr.cpMax - cr.cpMin); + if(lpstrText != NULL) + { + lLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText); + strText.ReleaseBuffer(); + } +#else // !(_RICHEDIT_VER >= 0x0200) + CTempBuffer buff; + LPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1); + if(lpstrText == NULL) + return 0; + LONG lLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText); + if(lLen == 0) + return 0; + + USES_CONVERSION; + strText = A2T(lpstrText); +#endif // !(_RICHEDIT_VER >= 0x0200) + + return lLen; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + WORD GetSelectionType() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (WORD)::SendMessage(m_hWnd, EM_SELECTIONTYPE, 0, 0L); + } + + COLORREF SetBackgroundColor(COLORREF cr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 0, cr); + } + + COLORREF SetBackgroundColor() // sets to system background + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 1, 0); + } + + BOOL SetCharFormat(CHARFORMAT& cf, WORD wFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf); + } + + BOOL SetDefaultCharFormat(CHARFORMAT& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf); + } + + BOOL SetSelectionCharFormat(CHARFORMAT& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + + BOOL SetWordCharFormat(CHARFORMAT& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf); + } + + DWORD SetEventMask(DWORD dwEventMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_SETEVENTMASK, 0, dwEventMask); + } + + BOOL SetParaFormat(PARAFORMAT& pf) + { + ATLASSERT(::IsWindow(m_hWnd)); + pf.cbSize = sizeof(PARAFORMAT); + return (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf); + } + + BOOL SetTargetDevice(HDC hDC, int cxLineWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTARGETDEVICE, (WPARAM)hDC, cxLineWidth); + } + + int GetTextLength() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L); + } + + BOOL SetReadOnly(BOOL bReadOnly = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L); + } + + int GetFirstVisibleLine() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L); + } + + EDITWORDBREAKPROCEX GetWordBreakProcEx() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_GETWORDBREAKPROCEX, 0, 0L); + } + + EDITWORDBREAKPROCEX SetWordBreakProcEx(EDITWORDBREAKPROCEX pfnEditWordBreakProcEx) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_SETWORDBREAKPROCEX, 0, (LPARAM)pfnEditWordBreakProcEx); + } + + int GetTextRange(TEXTRANGE* pTextRange) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)pTextRange); + } + +#if (_RICHEDIT_VER >= 0x0200) + int GetTextRange(LONG nStartChar, LONG nEndChar, LPTSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TEXTRANGE tr = { 0 }; + tr.chrg.cpMin = nStartChar; + tr.chrg.cpMax = nEndChar; + tr.lpstrText = lpstrText; + return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr); + } +#else // !(_RICHEDIT_VER >= 0x0200) + + int GetTextRange(LONG nStartChar, LONG nEndChar, LPSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + TEXTRANGE tr = { 0 }; + tr.chrg.cpMin = nStartChar; + tr.chrg.cpMax = nEndChar; + tr.lpstrText = lpstrText; + return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr); + } +#endif // !(_RICHEDIT_VER >= 0x0200) + +#if (_RICHEDIT_VER >= 0x0200) + DWORD GetDefaultCharFormat(CHARFORMAT2& cf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf); + } + + BOOL SetCharFormat(CHARFORMAT2& cf, WORD wFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf); + } + + BOOL SetDefaultCharFormat(CHARFORMAT2& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf); + } + + DWORD GetSelectionCharFormat(CHARFORMAT2& cf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf); + } + + BOOL SetSelectionCharFormat(CHARFORMAT2& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + + BOOL SetWordCharFormat(CHARFORMAT2& cf) + { + ATLASSERT(::IsWindow(m_hWnd)); + cf.cbSize = sizeof(CHARFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf); + } + + DWORD GetParaFormat(PARAFORMAT2& pf) const + { + ATLASSERT(::IsWindow(m_hWnd)); + pf.cbSize = sizeof(PARAFORMAT2); + return (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf); + } + + BOOL SetParaFormat(PARAFORMAT2& pf) + { + ATLASSERT(::IsWindow(m_hWnd)); + pf.cbSize = sizeof(PARAFORMAT2); + return (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf); + } + + TEXTMODE GetTextMode() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (TEXTMODE)::SendMessage(m_hWnd, EM_GETTEXTMODE, 0, 0L); + } + + BOOL SetTextMode(TEXTMODE enumTextMode) + { + ATLASSERT(::IsWindow(m_hWnd)); + return !(BOOL)::SendMessage(m_hWnd, EM_SETTEXTMODE, enumTextMode, 0L); + } + + UNDONAMEID GetUndoName() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UNDONAMEID)::SendMessage(m_hWnd, EM_GETUNDONAME, 0, 0L); + } + + UNDONAMEID GetRedoName() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UNDONAMEID)::SendMessage(m_hWnd, EM_GETREDONAME, 0, 0L); + } + + BOOL CanRedo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L); + } + + BOOL GetAutoURLDetect() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETAUTOURLDETECT, 0, 0L); + } + + BOOL SetAutoURLDetect(BOOL bAutoDetect = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return !(BOOL)::SendMessage(m_hWnd, EM_AUTOURLDETECT, bAutoDetect, 0L); + } + + // this method is deprecated, please use SetAutoURLDetect + BOOL EnableAutoURLDetect(BOOL bEnable = TRUE) { return SetAutoURLDetect(bEnable); } + + UINT SetUndoLimit(UINT uUndoLimit) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_SETUNDOLIMIT, uUndoLimit, 0L); + } + + void SetPalette(HPALETTE hPalette) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETPALETTE, (WPARAM)hPalette, 0L); + } + + int GetTextEx(GETTEXTEX* pGetTextEx, LPTSTR lpstrText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)pGetTextEx, (LPARAM)lpstrText); + } + + int GetTextEx(LPTSTR lpstrText, int nTextLen, DWORD dwFlags = GT_DEFAULT, UINT uCodePage = CP_ACP, LPCSTR lpDefaultChar = NULL, LPBOOL lpUsedDefChar = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + GETTEXTEX gte = { 0 }; + gte.cb = nTextLen * sizeof(TCHAR); + gte.codepage = uCodePage; + gte.flags = dwFlags; + gte.lpDefaultChar = lpDefaultChar; + gte.lpUsedDefChar = lpUsedDefChar; + return (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)>e, (LPARAM)lpstrText); + } + + int GetTextLengthEx(GETTEXTLENGTHEX* pGetTextLengthEx) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)pGetTextLengthEx, 0L); + } + + int GetTextLengthEx(DWORD dwFlags = GTL_DEFAULT, UINT uCodePage = CP_ACP) const + { + ATLASSERT(::IsWindow(m_hWnd)); + GETTEXTLENGTHEX gtle = { 0 }; + gtle.codepage = uCodePage; + gtle.flags = dwFlags; + return (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)>le, 0L); + } +#endif // (_RICHEDIT_VER >= 0x0200) + +#if (_RICHEDIT_VER >= 0x0300) + int SetTextEx(SETTEXTEX* pSetTextEx, LPCTSTR lpstrText) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)pSetTextEx, (LPARAM)lpstrText); + } + + int SetTextEx(LPCTSTR lpstrText, DWORD dwFlags = ST_DEFAULT, UINT uCodePage = CP_ACP) + { + ATLASSERT(::IsWindow(m_hWnd)); + SETTEXTEX ste = { 0 }; + ste.flags = dwFlags; + ste.codepage = uCodePage; + return (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpstrText); + } + + int GetEditStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_GETEDITSTYLE, 0, 0L); + } + + int SetEditStyle(int nStyle, int nMask = -1) + { + ATLASSERT(::IsWindow(m_hWnd)); + if(nMask == -1) + nMask = nStyle; // set everything specified + return (int)::SendMessage(m_hWnd, EM_SETEDITSTYLE, nStyle, nMask); + } + + BOOL SetFontSize(int nFontSizeDelta) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nFontSizeDelta >= -1637 && nFontSizeDelta <= 1638); + return (BOOL)::SendMessage(m_hWnd, EM_SETFONTSIZE, nFontSizeDelta, 0L); + } + + void GetScrollPos(LPPOINT lpPoint) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpPoint != NULL); + ::SendMessage(m_hWnd, EM_GETSCROLLPOS, 0, (LPARAM)lpPoint); + } + + void SetScrollPos(LPPOINT lpPoint) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpPoint != NULL); + ::SendMessage(m_hWnd, EM_SETSCROLLPOS, 0, (LPARAM)lpPoint); + } + + BOOL GetZoom(int& nNum, int& nDen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETZOOM, (WPARAM)&nNum, (LPARAM)&nDen); + } + + BOOL SetZoom(int nNum, int nDen) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nNum >= 0 && nNum <= 64); + ATLASSERT(nDen >= 0 && nDen <= 64); + return (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, nNum, nDen); + } + + BOOL SetZoomOff() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, 0, 0L); + } +#endif // (_RICHEDIT_VER >= 0x0300) + +// Operations + void LimitText(LONG nChars = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_EXLIMITTEXT, 0, nChars); + } + + int LineFromChar(LONG nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_EXLINEFROMCHAR, 0, nIndex); + } + + POINT PosFromChar(LONG nChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + POINT point = { 0, 0 }; + ::SendMessage(m_hWnd, EM_POSFROMCHAR, (WPARAM)&point, nChar); + return point; + } + + int CharFromPos(POINT pt) const + { + ATLASSERT(::IsWindow(m_hWnd)); + POINTL ptl = { pt.x, pt.y }; + return (int)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, (LPARAM)&ptl); + } + + void EmptyUndoBuffer() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L); + } + + int LineIndex(int nLine = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L); + } + + int LineLength(int nLine = -1) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L); + } + + BOOL LineScroll(int nLines, int nChars = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_LINESCROLL, nChars, nLines); + } + + void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText); + } + + void SetRect(LPCRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect); + } + + BOOL DisplayBand(LPRECT pDisplayRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_DISPLAYBAND, 0, (LPARAM)pDisplayRect); + } + + LONG FindText(DWORD dwFlags, FINDTEXT& ft) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE) + return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTW, dwFlags, (LPARAM)&ft); +#else + return (LONG)::SendMessage(m_hWnd, EM_FINDTEXT, dwFlags, (LPARAM)&ft); +#endif + } + + LONG FindText(DWORD dwFlags, FINDTEXTEX& ft) const + { + ATLASSERT(::IsWindow(m_hWnd)); +#if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE) + return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEXW, dwFlags, (LPARAM)&ft); +#else + return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEX, dwFlags, (LPARAM)&ft); +#endif + } + + LONG FormatRange(FORMATRANGE& fr, BOOL bDisplay = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)&fr); + } + + LONG FormatRange(FORMATRANGE* pFormatRange, BOOL bDisplay = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)pFormatRange); + } + + void HideSelection(BOOL bHide = TRUE, BOOL bChangeStyle = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_HIDESELECTION, bHide, bChangeStyle); + } + + void PasteSpecial(UINT uClipFormat, DWORD dwAspect = 0, HMETAFILE hMF = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + REPASTESPECIAL reps = { dwAspect, (DWORD_PTR)hMF }; + ::SendMessage(m_hWnd, EM_PASTESPECIAL, uClipFormat, (LPARAM)&reps); + } + + void RequestResize() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_REQUESTRESIZE, 0, 0L); + } + + LONG StreamIn(UINT uFormat, EDITSTREAM& es) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_STREAMIN, uFormat, (LPARAM)&es); + } + + LONG StreamOut(UINT uFormat, EDITSTREAM& es) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, uFormat, (LPARAM)&es); + } + + DWORD FindWordBreak(int nCode, LONG nStartChar) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_FINDWORDBREAK, nCode, nStartChar); + } + + // Additional operations + void ScrollCaret() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); + } + + int InsertText(long nInsertAfterChar, LPCTSTR lpstrText, BOOL bCanUndo = FALSE) + { + int nRet = SetSel(nInsertAfterChar, nInsertAfterChar); + ReplaceSel(lpstrText, bCanUndo); + return nRet; + } + + int AppendText(LPCTSTR lpstrText, BOOL bCanUndo = FALSE) + { + return InsertText(GetWindowTextLength(), lpstrText, bCanUndo); + } + + // Clipboard operations + BOOL Undo() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L); + } + + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); + } + + void Copy() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_COPY, 0, 0L); + } + + void Cut() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CUT, 0, 0L); + } + + void Paste() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); + } + + // OLE support + IRichEditOle* GetOleInterface() const + { + ATLASSERT(::IsWindow(m_hWnd)); + IRichEditOle *pRichEditOle = NULL; + ::SendMessage(m_hWnd, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle); + return pRichEditOle; + } + + BOOL SetOleCallback(IRichEditOleCallback* pCallback) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETOLECALLBACK, 0, (LPARAM)pCallback); + } + +#if (_RICHEDIT_VER >= 0x0200) + BOOL Redo() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_REDO, 0, 0L); + } + + void StopGroupTyping() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_STOPGROUPTYPING, 0, 0L); + } + + void ShowScrollBar(int nBarType, BOOL bVisible = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SHOWSCROLLBAR, nBarType, bVisible); + } +#endif // (_RICHEDIT_VER >= 0x0200) + +#if (_RICHEDIT_VER >= 0x0300) + BOOL SetTabStops(int nTabStops, LPINT rgTabStops) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops); + } + + BOOL SetTabStops() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L); + } + + BOOL SetTabStops(const int& cxEachStop) // takes an 'int' + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop); + } +#endif // (_RICHEDIT_VER >= 0x0300) +}; + +typedef CRichEditCtrlT CRichEditCtrl; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CRichEditCommands - message handlers for standard EDIT commands + +#ifndef _WIN32_WCE + +// Chain to CRichEditCommands message map. Your class must also derive from CRichEditCtrl. +// Example: +// class CMyRichEdit : public CWindowImpl, +// public CRichEditCommands +// { +// public: +// BEGIN_MSG_MAP(CMyRichEdit) +// // your handlers... +// CHAIN_MSG_MAP_ALT(CRichEditCommands, 1) +// END_MSG_MAP() +// // other stuff... +// }; + +template +class CRichEditCommands : public CEditCommands< T > +{ +public: + BEGIN_MSG_MAP(CRichEditCommands< T >) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_EDIT_CLEAR, CEditCommands< T >::OnEditClear) + COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, CEditCommands< T >::OnEditClearAll) + COMMAND_ID_HANDLER(ID_EDIT_COPY, CEditCommands< T >::OnEditCopy) + COMMAND_ID_HANDLER(ID_EDIT_CUT, CEditCommands< T >::OnEditCut) + COMMAND_ID_HANDLER(ID_EDIT_PASTE, CEditCommands< T >::OnEditPaste) + COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, CEditCommands< T >::OnEditSelectAll) + COMMAND_ID_HANDLER(ID_EDIT_UNDO, CEditCommands< T >::OnEditUndo) +#if (_RICHEDIT_VER >= 0x0200) + COMMAND_ID_HANDLER(ID_EDIT_REDO, OnEditRedo) +#endif // (_RICHEDIT_VER >= 0x0200) + END_MSG_MAP() + +#if (_RICHEDIT_VER >= 0x0200) + LRESULT OnEditRedo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Redo(); + return 0; + } +#endif // (_RICHEDIT_VER >= 0x0200) + +// State (update UI) helpers + BOOL CanCut() const + { return HasSelection(); } + + BOOL CanCopy() const + { return HasSelection(); } + + BOOL CanClear() const + { return HasSelection(); } + +// Implementation + BOOL HasSelection() const + { + const T* pT = static_cast(this); + return (pT->GetSelectionType() != SEL_EMPTY); + } +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CDragListBox + +#ifndef _WIN32_WCE + +template +class CDragListBoxT : public CListBoxT< TBase > +{ +public: +// Constructors + CDragListBoxT(HWND hWnd = NULL) : CListBoxT< TBase >(hWnd) + { } + + CDragListBoxT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + if(hWnd != NULL) + MakeDragList(); + return hWnd; + } + +// Operations + BOOL MakeDragList() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0); + return ::MakeDragList(m_hWnd); + } + + int LBItemFromPt(POINT pt, BOOL bAutoScroll = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::LBItemFromPt(m_hWnd, pt, bAutoScroll); + } + + void DrawInsert(int nItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::DrawInsert(GetParent(), m_hWnd, nItem); + } + + static UINT GetDragListMessage() + { + static UINT uDragListMessage = 0; + if(uDragListMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CDragListBox::GetDragListMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uDragListMessage == 0) + uDragListMessage = ::RegisterWindowMessage(DRAGLISTMSGSTRING); + + lock.Unlock(); + } + ATLASSERT(uDragListMessage != 0); + return uDragListMessage; + } +}; + +typedef CDragListBoxT CDragListBox; + +template +class CDragListNotifyImpl +{ +public: + BEGIN_MSG_MAP(CDragListNotifyImpl< T >) + MESSAGE_HANDLER(CDragListBox::GetDragListMessage(), OnDragListNotify) + END_MSG_MAP() + + LRESULT OnDragListNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + uMsg; // avoid level 4 warning + ATLASSERT(uMsg == CDragListBox::GetDragListMessage()); + T* pT = static_cast(this); + LPDRAGLISTINFO lpDragListInfo = (LPDRAGLISTINFO)lParam; + LRESULT lRet = 0; + switch(lpDragListInfo->uNotification) + { + case DL_BEGINDRAG: + lRet = (LPARAM)pT->OnBeginDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); + break; + case DL_CANCELDRAG: + pT->OnCancelDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); + break; + case DL_DRAGGING: + lRet = (LPARAM)pT->OnDragging((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); + break; + case DL_DROPPED: + pT->OnDropped((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("Unknown DragListBox notification\n")); + bHandled = FALSE; // don't handle it + break; + } + return lRet; + } + +// Overrideables + BOOL OnBeginDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) + { + return TRUE; // allow dragging + } + + void OnCancelDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) + { + // nothing to do + } + + int OnDragging(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) + { + return 0; // don't change cursor + } + + void OnDropped(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) + { + // nothing to do + } +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CReBarCtrl + +template +class CReBarCtrlT : public TBase +{ +public: +// Constructors + CReBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CReBarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return REBARCLASSNAME; + } + + UINT GetBandCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, RB_GETBANDCOUNT, 0, 0L); + } + + BOOL GetBandInfo(int nBand, LPREBARBANDINFO lprbbi) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_GETBANDINFO, nBand, (LPARAM)lprbbi); + } + + BOOL SetBandInfo(int nBand, LPREBARBANDINFO lprbbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SETBANDINFO, nBand, (LPARAM)lprbbi); + } + + BOOL GetBarInfo(LPREBARINFO lprbi) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)lprbi); + } + + BOOL SetBarInfo(LPREBARINFO lprbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)lprbi); + } + + CImageList GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + REBARINFO rbi = { 0 }; + rbi.cbSize = sizeof(REBARINFO); + rbi.fMask = RBIM_IMAGELIST; + if( (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)&rbi) == FALSE ) return CImageList(); + return CImageList(rbi.himl); + } + + BOOL SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + REBARINFO rbi = { 0 }; + rbi.cbSize = sizeof(REBARINFO); + rbi.fMask = RBIM_IMAGELIST; + rbi.himl = hImageList; + return (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)&rbi); + } + + UINT GetRowCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, RB_GETROWCOUNT, 0, 0L); + } + + UINT GetRowHeight(int nBand) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, RB_GETROWHEIGHT, nBand, 0L); + } + +#if (_WIN32_IE >= 0x0400) + COLORREF GetTextColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, RB_GETTEXTCOLOR, 0, 0L); + } + + COLORREF SetTextColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, RB_SETTEXTCOLOR, 0, (LPARAM)clr); + } + + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, RB_GETBKCOLOR, 0, 0L); + } + + COLORREF SetBkColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, RB_SETBKCOLOR, 0, (LPARAM)clr); + } + + UINT GetBarHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, RB_GETBARHEIGHT, 0, 0L); + } + + BOOL GetRect(int nBand, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_GETRECT, nBand, (LPARAM)lpRect); + } + +#ifndef _WIN32_WCE + CToolTipCtrl GetToolTips() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CToolTipCtrl((HWND)::SendMessage(m_hWnd, RB_GETTOOLTIPS, 0, 0L)); + } + + void SetToolTips(HWND hwndToolTip) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_SETTOOLTIPS, (WPARAM)hwndToolTip, 0L); + } +#endif // !_WIN32_WCE + + void GetBandBorders(int nBand, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpRect != NULL); + ::SendMessage(m_hWnd, RB_GETBANDBORDERS, nBand, (LPARAM)lpRect); + } + +#ifndef _WIN32_WCE + BOOL GetColorScheme(LPCOLORSCHEME lpColorScheme) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpColorScheme != NULL); + return (BOOL)::SendMessage(m_hWnd, RB_GETCOLORSCHEME, 0, (LPARAM)lpColorScheme); + } + + void SetColorScheme(LPCOLORSCHEME lpColorScheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpColorScheme != NULL); + ::SendMessage(m_hWnd, RB_SETCOLORSCHEME, 0, (LPARAM)lpColorScheme); + } + + HPALETTE GetPalette() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HPALETTE)::SendMessage(m_hWnd, RB_GETPALETTE, 0, 0L); + } + + HPALETTE SetPalette(HPALETTE hPalette) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HPALETTE)::SendMessage(m_hWnd, RB_SETPALETTE, 0, (LPARAM)hPalette); + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_WINNT >= 0x0501) + // requires uxtheme.h to be included to use MARGINS struct +#ifndef _UXTHEME_H_ + typedef struct _MARGINS* PMARGINS; +#endif // !_UXTHEME_H_ + void GetBandMargins(PMARGINS pMargins) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_GETBANDMARGINS, 0, (LPARAM)pMargins); + } + + void SetWindowTheme(LPCWSTR lpstrTheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); + } +#endif // (_WIN32_WINNT >= 0x0501) + +#if (_WIN32_IE >= 0x0600) + DWORD GetExtendedStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, RB_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, RB_SETEXTENDEDSTYLE, dwMask, dwStyle); + } +#endif // (_WIN32_IE >= 0x0600) + +// Operations + BOOL InsertBand(int nBand, LPREBARBANDINFO lprbbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_INSERTBAND, nBand, (LPARAM)lprbbi); + } + + BOOL AddBand(LPREBARBANDINFO lprbbi) + { + return InsertBand(-1, lprbbi); + } + + BOOL DeleteBand(int nBand) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_DELETEBAND, nBand, 0L); + } + + ATL::CWindow SetNotifyWnd(HWND hWnd) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow((HWND)::SendMessage(m_hWnd, RB_SETPARENT, (WPARAM)hWnd, 0L)); + } + +#if (_WIN32_IE >= 0x0400) + void BeginDrag(int nBand, DWORD dwPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, dwPos); + } + + void BeginDrag(int nBand, int xPos, int yPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, MAKELPARAM(xPos, yPos)); + } + + void EndDrag() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_ENDDRAG, 0, 0L); + } + + void DragMove(DWORD dwPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_DRAGMOVE, 0, dwPos); + } + + void DragMove(int xPos, int yPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_DRAGMOVE, 0, MAKELPARAM(xPos, yPos)); + } + +#ifndef _WIN32_WCE + void GetDropTarget(IDropTarget** ppDropTarget) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_GETDROPTARGET, 0, (LPARAM)ppDropTarget); + } +#endif // !_WIN32_WCE + + void MaximizeBand(int nBand, BOOL bIdeal = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_MAXIMIZEBAND, nBand, bIdeal); + } + + void MinimizeBand(int nBand) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_MINIMIZEBAND, nBand, 0L); + } + + BOOL SizeToRect(LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SIZETORECT, 0, (LPARAM)lpRect); + } + + int IdToIndex(UINT uBandID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, RB_IDTOINDEX, uBandID, 0L); + } + + int HitTest(LPRBHITTESTINFO lprbht) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, RB_HITTEST, 0, (LPARAM)lprbht); + } + + BOOL ShowBand(int nBand, BOOL bShow) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SHOWBAND, nBand, bShow); + } + +#ifndef _WIN32_WCE + BOOL MoveBand(int nBand, int nNewPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nNewPos >= 0 && nNewPos <= ((int)GetBandCount() - 1)); + return (BOOL)::SendMessage(m_hWnd, RB_MOVEBAND, nBand, nNewPos); + } +#endif // !_WIN32_WCE +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + void PushChevron(int nBand, LPARAM lAppValue) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, RB_PUSHCHEVRON, nBand, lAppValue); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Extra operations +#if (_WIN32_IE >= 0x0400) + void LockBands(bool bLock) + { + int nBandCount = GetBandCount(); + for(int i =0; i < nBandCount; i++) + { + REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() }; + rbbi.fMask = RBBIM_STYLE; + BOOL bRet = GetBandInfo(i, &rbbi); + ATLASSERT(bRet); + + if((rbbi.fStyle & RBBS_GRIPPERALWAYS) == 0) + { + rbbi.fStyle |= RBBS_GRIPPERALWAYS; + bRet = SetBandInfo(i, &rbbi); + ATLASSERT(bRet); + rbbi.fStyle &= ~RBBS_GRIPPERALWAYS; + } + + if(bLock) + rbbi.fStyle |= RBBS_NOGRIPPER; + else + rbbi.fStyle &= ~RBBS_NOGRIPPER; + + bRet = SetBandInfo(i, &rbbi); + ATLASSERT(bRet); + } + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_WINNT >= 0x0600) + BOOL SetBandWidth(int nBand, int cxWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, RB_SETBANDWIDTH, nBand, cxWidth); + } +#endif // (_WIN32_WINNT >= 0x0600) +}; + +typedef CReBarCtrlT CReBarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CComboBoxEx + +#ifndef _WIN32_WCE + +template +class CComboBoxExT : public CComboBoxT< TBase > +{ +public: +// Constructors + CComboBoxExT(HWND hWnd = NULL) : CComboBoxT< TBase >(hWnd) + { } + + CComboBoxExT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_COMBOBOXEX; + } + + CImageList GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_GETIMAGELIST, 0, 0L)); + } + + CImageList SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_SETIMAGELIST, 0, (LPARAM)hImageList)); + } + +#if (_WIN32_IE >= 0x0400) + DWORD GetExtendedStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, CBEM_GETEXTENDEDSTYLE, 0, 0L); + } + + DWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, CBEM_SETEXTENDEDSTYLE, dwExMask, dwExStyle); + } + + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_WINNT >= 0x0501) + void SetWindowTheme(LPCWSTR lpstrTheme) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, CBEM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); + } +#endif // (_WIN32_WINNT >= 0x0501) + +// Operations + int InsertItem(const COMBOBOXEXITEM* lpcCBItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)lpcCBItem); + } + + int InsertItem(UINT nMask, int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage, + int iIndent, int iOverlay, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = nMask; + cbex.iItem = nIndex; + cbex.pszText = (LPTSTR) lpszItem; + cbex.iImage = nImage; + cbex.iSelectedImage = nSelImage; + cbex.iIndent = iIndent; + cbex.iOverlay = iOverlay; + cbex.lParam = lParam; + return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex); + } + + int InsertItem(int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_INDENT | CBEIF_LPARAM; + cbex.iItem = nIndex; + cbex.pszText = (LPTSTR) lpszItem; + cbex.iImage = nImage; + cbex.iSelectedImage = nSelImage; + cbex.iIndent = iIndent; + cbex.lParam = lParam; + return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex); + } + + int AddItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, int iOverlay, LPARAM lParam) + { + return InsertItem(nMask, -1, lpszItem, nImage, nSelImage, iIndent, iOverlay, lParam); + } + + int AddItem(LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0) + { + return InsertItem(-1, lpszItem, nImage, nSelImage, iIndent, lParam); + } + + int DeleteItem(int nIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, CBEM_DELETEITEM, nIndex, 0L); + } + + BOOL GetItem(PCOMBOBOXEXITEM pCBItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)pCBItem); + } + + BOOL SetItem(const COMBOBOXEXITEM* lpcCBItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)lpcCBItem); + } + + int SetItem(int nIndex, UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage, + int iIndent, int iOverlay, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = nMask; + cbex.iItem = nIndex; + cbex.pszText = (LPTSTR) lpszItem; + cbex.iImage = nImage; + cbex.iSelectedImage = nSelImage; + cbex.iIndent = iIndent; + cbex.iOverlay = iOverlay; + cbex.lParam = lParam; + return (int)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)&cbex); + } + + BOOL GetItemText(int nIndex, LPTSTR lpszItem, int nLen) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpszItem != NULL); + + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = CBEIF_TEXT; + cbex.iItem = nIndex; + cbex.pszText = lpszItem; + cbex.cchTextMax = nLen; + + return (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex); + } + +#ifndef _ATL_NO_COM + BOOL GetItemText(int nIndex, BSTR& bstrText) const + { + USES_CONVERSION; + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(bstrText == NULL); + + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = CBEIF_TEXT; + cbex.iItem = nIndex; + + LPTSTR lpstrText = NULL; + BOOL bRet = FALSE; + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrText = new TCHAR[nLen]); + if(lpstrText == NULL) + break; + lpstrText[0] = NULL; + cbex.pszText = lpstrText; + cbex.cchTextMax = nLen; + bRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex); + if(!bRet || (lstrlen(cbex.pszText) < nLen - 1)) + break; + delete [] lpstrText; + lpstrText = NULL; + } + + if(lpstrText != NULL) + { + if(bRet) + bstrText = ::SysAllocString(T2OLE(lpstrText)); + delete [] lpstrText; + } + + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL GetItemText(int nIndex, _CSTRING_NS::CString& strText) const + { + ATLASSERT(::IsWindow(m_hWnd)); + + COMBOBOXEXITEM cbex = { 0 }; + cbex.mask = CBEIF_TEXT; + cbex.iItem = nIndex; + + strText.Empty(); + BOOL bRet = FALSE; + for(int nLen = 256; ; nLen *= 2) + { + cbex.pszText = strText.GetBufferSetLength(nLen); + if(cbex.pszText == NULL) + { + bRet = FALSE; + break; + } + cbex.cchTextMax = nLen; + bRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex); + if(!bRet || (lstrlen(cbex.pszText) < nLen - 1)) + break; + } + strText.ReleaseBuffer(); + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL SetItemText(int nIndex, LPCTSTR lpszItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return SetItem(nIndex, CBEIF_TEXT, lpszItem, 0, 0, 0, 0, 0); + } + + CComboBox GetComboCtrl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CComboBox((HWND)::SendMessage(m_hWnd, CBEM_GETCOMBOCONTROL, 0, 0L)); + } + + CEdit GetEditCtrl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CEdit((HWND)::SendMessage(m_hWnd, CBEM_GETEDITCONTROL, 0, 0L)); + } + + BOOL HasEditChanged() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, CBEM_HASEDITCHANGED, 0, 0L); + } + +// Non-functional + int AddString(LPCTSTR /*lpszItem*/) + { + ATLASSERT(FALSE); // Not available in CComboBoxEx; use InsertItem + return 0; + } + + int InsertString(int /*nIndex*/, LPCTSTR /*lpszString*/) + { + ATLASSERT(FALSE); // Not available in CComboBoxEx; use InsertItem + return 0; + } + + int Dir(UINT /*attr*/, LPCTSTR /*lpszWildCard*/) + { + ATLASSERT(FALSE); // Not available in CComboBoxEx + return 0; + } + + int FindString(int /*nStartAfter*/, LPCTSTR /*lpszString*/) const + { + ATLASSERT(FALSE); // Not available in CComboBoxEx; try FindStringExact + return 0; + } +}; + +typedef CComboBoxExT CComboBoxEx; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMonthCalendarCtrl + +template +class CMonthCalendarCtrlT : public TBase +{ +public: +// Constructors + CMonthCalendarCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CMonthCalendarCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return MONTHCAL_CLASS; + } + + COLORREF GetColor(int nColorType) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, MCM_GETCOLOR, nColorType, 0L); + } + + COLORREF SetColor(int nColorType, COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, MCM_SETCOLOR, nColorType, clr); + } + + BOOL GetCurSel(LPSYSTEMTIME lpSysTime) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETCURSEL, 0, (LPARAM)lpSysTime); + } + + BOOL SetCurSel(LPSYSTEMTIME lpSysTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETCURSEL, 0, (LPARAM)lpSysTime); + } + + int GetFirstDayOfWeek(BOOL* pbLocaleVal = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_GETFIRSTDAYOFWEEK, 0, 0L); + if(pbLocaleVal != NULL) + *pbLocaleVal = (BOOL)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + + int SetFirstDayOfWeek(int nDay, BOOL* pbLocaleVal = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + DWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_SETFIRSTDAYOFWEEK, 0, nDay); + if(pbLocaleVal != NULL) + *pbLocaleVal = (BOOL)HIWORD(dwRet); + return (int)(short)LOWORD(dwRet); + } + + int GetMaxSelCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETMAXSELCOUNT, 0, 0L); + } + + BOOL SetMaxSelCount(int nMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETMAXSELCOUNT, nMax, 0L); + } + + int GetMonthDelta() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETMONTHDELTA, 0, 0L); + } + + int SetMonthDelta(int nDelta) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_SETMONTHDELTA, nDelta, 0L); + } + + DWORD GetRange(LPSYSTEMTIME lprgSysTimeArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, MCM_GETRANGE, 0, (LPARAM)lprgSysTimeArray); + } + + BOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETRANGE, dwFlags, (LPARAM)lprgSysTimeArray); + } + + BOOL GetSelRange(LPSYSTEMTIME lprgSysTimeArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETSELRANGE, 0, (LPARAM)lprgSysTimeArray); + } + + BOOL SetSelRange(LPSYSTEMTIME lprgSysTimeArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETSELRANGE, 0, (LPARAM)lprgSysTimeArray); + } + + BOOL GetToday(LPSYSTEMTIME lpSysTime) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETTODAY, 0, (LPARAM)lpSysTime); + } + + void SetToday(LPSYSTEMTIME lpSysTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, MCM_SETTODAY, 0, (LPARAM)lpSysTime); + } + + BOOL GetMinReqRect(LPRECT lpRectInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETMINREQRECT, 0, (LPARAM)lpRectInfo); + } + + int GetMaxTodayWidth() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETMAXTODAYWIDTH, 0, 0L); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetUnicodeFormat() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETUNICODEFORMAT, 0, 0L); + } + + BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETUNICODEFORMAT, bUnicode, 0L); + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + DWORD GetCurrentView() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, MCM_GETCURRENTVIEW, 0, 0L); + } + + BOOL SetCurrentView(DWORD dwView) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETCURRENTVIEW, 0, dwView); + } + + DWORD GetCalendarCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, MCM_GETCALENDARCOUNT, 0, 0L); + } + + BOOL GetCalendarGridInfo(PMCGRIDINFO pGridInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_GETCALENDARGRIDINFO, 0, (LPARAM)pGridInfo); + } + + CALID GetCALID() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (CALID)::SendMessage(m_hWnd, MCM_GETCALID, 0, 0L); + } + + void SetCALID(CALID calid) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, MCM_SETCALID, (LPARAM)calid, 0L); + } + + int GetCalendarBorder() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETCALENDARBORDER, 0, 0L); + } + + void SetCalendarBorder(int cxyBorder, BOOL bSet = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, MCM_SETCALENDARBORDER, (WPARAM)bSet, (LPARAM)cxyBorder); + } +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + +// Operations + int GetMonthRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, MCM_GETMONTHRANGE, dwFlags, (LPARAM)lprgSysTimeArray); + } + + BOOL SetDayState(int nMonths, LPMONTHDAYSTATE lpDayStateArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, MCM_SETDAYSTATE, nMonths, (LPARAM)lpDayStateArray); + } + + DWORD HitTest(PMCHITTESTINFO pMCHitTest) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, MCM_HITTEST, 0, (LPARAM)pMCHitTest); + } + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + void SizeRectToMin(LPRECT lpRect) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, MCM_SIZERECTTOMIN, 0, (LPARAM)lpRect); + } +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) +}; + +typedef CMonthCalendarCtrlT CMonthCalendarCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CDateTimePickerCtrl + +template +class CDateTimePickerCtrlT : public TBase +{ +public: +// Constructors + CDateTimePickerCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CDateTimePickerCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Operations + static LPCTSTR GetWndClassName() + { + return DATETIMEPICK_CLASS; + } + + BOOL SetFormat(LPCTSTR lpszFormat) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DTM_SETFORMAT, 0, (LPARAM)lpszFormat); + } + + COLORREF GetMonthCalColor(int nColorType) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, DTM_GETMCCOLOR, nColorType, 0L); + } + + COLORREF SetMonthCalColor(int nColorType, COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, DTM_SETMCCOLOR, nColorType, clr); + } + + DWORD GetRange(LPSYSTEMTIME lpSysTimeArray) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, DTM_GETRANGE, 0, (LPARAM)lpSysTimeArray); + } + + BOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lpSysTimeArray) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DTM_SETRANGE, dwFlags, (LPARAM)lpSysTimeArray); + } + + DWORD GetSystemTime(LPSYSTEMTIME lpSysTime) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)lpSysTime); + } + + BOOL SetSystemTime(DWORD dwFlags, LPSYSTEMTIME lpSysTime) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DTM_SETSYSTEMTIME, dwFlags, (LPARAM)lpSysTime); + } + + CMonthCalendarCtrl GetMonthCal() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CMonthCalendarCtrl((HWND)::SendMessage(m_hWnd, DTM_GETMONTHCAL, 0, 0L)); + } + +#if (_WIN32_IE >= 0x0400) + CFontHandle GetMonthCalFont() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CFontHandle((HFONT)::SendMessage(m_hWnd, DTM_GETMCFONT, 0, 0L)); + } + + void SetMonthCalFont(HFONT hFont, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_SETMCFONT, (WPARAM)hFont, MAKELPARAM(bRedraw, 0)); + } +#endif // (_WIN32_IE >= 0x0400) + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + DWORD GetMonthCalStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, DTM_GETMCSTYLE, 0, 0L); + } + + DWORD SetMonthCalStyle(DWORD dwStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, DTM_SETMCSTYLE, 0, (LPARAM)dwStyle); + } + + void GetDateTimePickerInfo(LPDATETIMEPICKERINFO lpPickerInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_GETDATETIMEPICKERINFO, 0, (LPARAM)lpPickerInfo); + } + + BOOL GetIdealSize(LPSIZE lpSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DTM_GETIDEALSIZE, 0, (LPARAM)lpSize); + } + + void CloseMonthCal() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_CLOSEMONTHCAL, 0, 0L); + } +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) +}; + +typedef CDateTimePickerCtrlT CDateTimePickerCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CFlatScrollBarImpl - support for flat scroll bars + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +template +class CFlatScrollBarImpl +{ +public: +// Initialization + BOOL FlatSB_Initialize() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::InitializeFlatSB(pT->m_hWnd); + } + + HRESULT FlatSB_Uninitialize() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::UninitializeFlatSB(pT->m_hWnd); + } + +// Flat scroll bar properties + BOOL FlatSB_GetScrollProp(UINT uIndex, LPINT lpnValue) const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_GetScrollProp(pT->m_hWnd, uIndex, lpnValue); + } + + BOOL FlatSB_SetScrollProp(UINT uIndex, int nValue, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_SetScrollProp(pT->m_hWnd, uIndex, nValue, bRedraw); + } + +// Attributes + int FlatSB_GetScrollPos(int nBar) const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_GetScrollPos(pT->m_hWnd, nBar); + } + + int FlatSB_SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_SetScrollPos(pT->m_hWnd, nBar, nPos, bRedraw); + } + + BOOL FlatSB_GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_GetScrollRange(pT->m_hWnd, nBar, lpMinPos, lpMaxPos); + } + + BOOL FlatSB_SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_SetScrollRange(pT->m_hWnd, nBar, nMinPos, nMaxPos, bRedraw); + } + + BOOL FlatSB_GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo) const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_GetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo); + } + + int FlatSB_SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_SetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo, bRedraw); + } + +// Operations + BOOL FlatSB_ShowScrollBar(UINT nBar, BOOL bShow = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_ShowScrollBar(pT->m_hWnd, nBar, bShow); + } + + BOOL FlatSB_EnableScrollBar(UINT uSBFlags, UINT uArrowFlags = ESB_ENABLE_BOTH) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::FlatSB_EnableScrollBar(pT->m_hWnd, uSBFlags, uArrowFlags); + } +}; + +template +class CFlatScrollBarT : public TBase, public CFlatScrollBarImpl > +{ +public: + CFlatScrollBarT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CFlatScrollBarT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } +}; + +typedef CFlatScrollBarT CFlatScrollBar; + +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CIPAddressCtrl + +#if (_WIN32_IE >= 0x0400) + +template +class CIPAddressCtrlT : public TBase +{ +public: +// Constructors + CIPAddressCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CIPAddressCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Atteributes + static LPCTSTR GetWndClassName() + { + return WC_IPADDRESS; + } + + BOOL IsBlank() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, IPM_ISBLANK, 0, 0L); + } + + int GetAddress(LPDWORD lpdwAddress) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, IPM_GETADDRESS, 0, (LPARAM)lpdwAddress); + } + + void SetAddress(DWORD dwAddress) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_SETADDRESS, 0, dwAddress); + } + + void ClearAddress() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_CLEARADDRESS, 0, 0L); + } + + void SetRange(int nField, WORD wRange) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_SETRANGE, nField, wRange); + } + + void SetRange(int nField, BYTE nMin, BYTE nMax) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_SETRANGE, nField, MAKEIPRANGE(nMin, nMax)); + } + + void SetFocus(int nField) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IPM_SETFOCUS, nField, 0L); + } +}; + +typedef CIPAddressCtrlT CIPAddressCtrl; + +#endif // (_WIN32_IE >= 0x0400) + + +/////////////////////////////////////////////////////////////////////////////// +// CPagerCtrl + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +template +class CPagerCtrlT : public TBase +{ +public: +// Constructors + CPagerCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CPagerCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_PAGESCROLLER; + } + + int GetButtonSize() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_GETBUTTONSIZE, 0, 0L); + } + + int SetButtonSize(int nButtonSize) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_SETBUTTONSIZE, 0, nButtonSize); + } + + DWORD GetButtonState(int nButton) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nButton == PGB_TOPORLEFT || nButton == PGB_BOTTOMORRIGHT); + return (DWORD)::SendMessage(m_hWnd, PGM_GETBUTTONSTATE, 0, nButton); + } + + COLORREF GetBkColor() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PGM_GETBKCOLOR, 0, 0L); + } + + COLORREF SetBkColor(COLORREF clrBk) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (COLORREF)::SendMessage(m_hWnd, PGM_SETBKCOLOR, 0, (LPARAM)clrBk); + } + + int GetBorder() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_GETBORDER, 0, 0L); + } + + int SetBorder(int nBorderSize) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_SETBORDER, 0, nBorderSize); + } + + int GetPos() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_GETPOS, 0, 0L); + } + + int SetPos(int nPos) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PGM_SETPOS, 0, nPos); + } + +// Operations + void SetChild(HWND hWndChild) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PGM_SETCHILD, 0, (LPARAM)hWndChild); + } + + void ForwardMouse(BOOL bForward = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PGM_FORWARDMOUSE, bForward, 0L); + } + + void RecalcSize() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PGM_RECALCSIZE, 0, 0L); + } + + void GetDropTarget(IDropTarget** ppDropTarget) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(ppDropTarget != NULL); + ::SendMessage(m_hWnd, PGM_GETDROPTARGET, 0, (LPARAM)ppDropTarget); + } +}; + +typedef CPagerCtrlT CPagerCtrl; + +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CLinkCtrl - Windows SYSLINK control + +#if (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE) + +template +class CLinkCtrlT : public TBase +{ +public: +// Constructors + CLinkCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CLinkCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + } + +// Attributes + static LPCTSTR GetWndClassName() + { +#ifdef _UNICODE + return WC_LINK; +#else // !_UNICODE + return "SysLink"; +#endif // !_UNICODE + } + + int GetIdealHeight(int cxMaxWidth = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LM_GETIDEALHEIGHT, cxMaxWidth, 0L); + } + + BOOL GetItem(PLITEM pLItem) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LM_GETITEM, 0, (LPARAM)pLItem); + } + + BOOL SetItem(PLITEM pLItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LM_SETITEM, 0, (LPARAM)pLItem); + } + + // Vista only + int GetIdealSize(SIZE& size, int cxMaxWidth = 0) const + { +#ifndef LM_GETIDEALSIZE + const UINT LM_GETIDEALSIZE = LM_GETIDEALHEIGHT; +#endif + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, LM_GETIDEALSIZE, cxMaxWidth, (LPARAM)&size); + } + +// Operations + BOOL HitTest(PLHITTESTINFO pLHitTestInfo) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, LM_HITTEST, 0, (LPARAM)pLHitTestInfo); + } +}; + +typedef CLinkCtrlT CLinkCtrl; + +#endif // (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CCustomDraw - MI class for custom-draw support + +template +class CCustomDraw +{ +public: +#if (_ATL_VER < 0x0700) + BOOL m_bHandledCD; + + BOOL IsMsgHandled() const + { + return m_bHandledCD; + } + + void SetMsgHandled(BOOL bHandled) + { + m_bHandledCD = bHandled; + } +#endif // !(_ATL_VER < 0x0700) + +// Message map and handlers + BEGIN_MSG_MAP(CCustomDraw< T >) + NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw) + ALT_MSG_MAP(1) + REFLECTED_NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw) + END_MSG_MAP() + +// message handler + LRESULT OnCustomDraw(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + LPNMCUSTOMDRAW lpNMCustomDraw = (LPNMCUSTOMDRAW)pnmh; + DWORD dwRet = 0; + switch(lpNMCustomDraw->dwDrawStage) + { + case CDDS_PREPAINT: + dwRet = pT->OnPrePaint(idCtrl, lpNMCustomDraw); + break; + case CDDS_POSTPAINT: + dwRet = pT->OnPostPaint(idCtrl, lpNMCustomDraw); + break; + case CDDS_PREERASE: + dwRet = pT->OnPreErase(idCtrl, lpNMCustomDraw); + break; + case CDDS_POSTERASE: + dwRet = pT->OnPostErase(idCtrl, lpNMCustomDraw); + break; + case CDDS_ITEMPREPAINT: + dwRet = pT->OnItemPrePaint(idCtrl, lpNMCustomDraw); + break; + case CDDS_ITEMPOSTPAINT: + dwRet = pT->OnItemPostPaint(idCtrl, lpNMCustomDraw); + break; + case CDDS_ITEMPREERASE: + dwRet = pT->OnItemPreErase(idCtrl, lpNMCustomDraw); + break; + case CDDS_ITEMPOSTERASE: + dwRet = pT->OnItemPostErase(idCtrl, lpNMCustomDraw); + break; +#if (_WIN32_IE >= 0x0400) + case (CDDS_ITEMPREPAINT | CDDS_SUBITEM): + dwRet = pT->OnSubItemPrePaint(idCtrl, lpNMCustomDraw); + break; +#endif // (_WIN32_IE >= 0x0400) + default: + pT->SetMsgHandled(FALSE); + break; + } + bHandled = pT->IsMsgHandled(); + return dwRet; + } + +// Overrideables + DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnItemPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + + DWORD OnItemPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } + +#if (_WIN32_IE >= 0x0400) + DWORD OnSubItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_DODEFAULT; + } +#endif // (_WIN32_IE >= 0x0400) +}; + + +// --- Windows CE common controls --- + +#ifdef _WIN32_WCE + +/////////////////////////////////////////////////////////////////////////////// +// CCECommandBarCtrl + +template +class CCECommandBarCtrlT : public TBase +{ +public: +// Constructors + CCECommandBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } + + CCECommandBarCtrlT< TBase >& operator=(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + BOOL IsVisible() const + { + return IsWindowVisible(); + } + + int GetHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_Height(m_hWnd); + } + + HMENU GetMenu(WORD wButton) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_GetMenu(m_hWnd, wButton); + } + +// Operations + HWND Create(HWND hWndParent, int nCmdBarID) + { + m_hWnd = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), hWndParent, nCmdBarID); + ATLASSERT(::IsWindow(m_hWnd)); + return m_hWnd; + } + + void Destroy() + { + DestroyWindow(); + } + + BOOL Show(BOOL bShow = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_Show(m_hWnd, bShow); + } + + BOOL DrawMenuBar(WORD wButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_DrawMenuBar(m_hWnd, wButton); + } + + BOOL AddAdornments(DWORD dwFlags = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_AddAdornments(m_hWnd, dwFlags, 0); + } + + int AddBitmap(int nBitmapID, int nNumImages) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_AddBitmap(m_hWnd, ModuleHelper::GetResourceInstance(), nBitmapID, nNumImages, 16, 16); + } + + BOOL AddButtons(UINT uNumButtons, LPTBBUTTON lpButtons) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CommandBar_AddButtons(m_hWnd, uNumButtons, lpButtons); + } + + BOOL AddToolTips(UINT uNumToolTips, LPTSTR lpToolTips) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CommandBar_AddToolTips(m_hWnd, uNumToolTips, lpToolTips); + } + + BOOL InsertButton(int nButton, LPTBBUTTON lpButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return CommandBar_InsertButton(m_hWnd, nButton, lpButton); + } + + HWND InsertComboBox(int nWidth, UINT dwStyle, WORD wComboBoxID, WORD wButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_InsertComboBox(m_hWnd, ModuleHelper::GetModuleInstance(), nWidth, dwStyle, wComboBoxID, wButton); + } + + BOOL InsertMenubar(WORD wMenuID, WORD wButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_InsertMenubar(m_hWnd, ModuleHelper::GetResourceInstance(), wMenuID, wButton); + } + + BOOL InsertMenubarEx(ATL::_U_STRINGorID menu, WORD wButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBar_InsertMenubarEx(m_hWnd, ModuleHelper::GetResourceInstance(), (LPTSTR)menu.m_lpstr, wButton); + } + + BOOL IsCommandBarMessage(LPMSG lpMsg) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::IsCommandBarMessage(m_hWnd, lpMsg); + } +}; + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC MenuBar + typedef CCECommandBarCtrlT CMenuBarCtrl; +#else + typedef CCECommandBarCtrlT CCECommandBarCtrl; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + +/////////////////////////////////////////////////////////////////////////////// +// CCECommandBandsCtrl + +template +class CCECommandBandsCtrlT : public TBase +{ +public: +// Constructors + CCECommandBandsCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } + + CCECommandBandsCtrlT< TBase >& operator=(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + BOOL IsVisible() const + { + return IsWindowVisible(); + } + +#if (_WIN32_IE >= 0x0400) + UINT GetHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CommandBands_Height(m_hWnd); + } +#endif // (_WIN32_IE >= 0x0400) + + HWND GetCommandBar(UINT uBand) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_GetCommandBar(m_hWnd, uBand); + } + + BOOL GetRestoreInformation(UINT uBand, LPCOMMANDBANDSRESTOREINFO pcbr) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_GetRestoreInformation(m_hWnd, uBand, pcbr); + } + +// Operations + HWND Create(HWND hWndParent, UINT wID, DWORD dwStyles, HIMAGELIST hImageList = NULL) + { + m_hWnd = ::CommandBands_Create(ModuleHelper::GetModuleInstance(), hWndParent, wID, dwStyles, hImageList); + ATLASSERT(::IsWindow(m_hWnd)); + return m_hWnd; + } + + BOOL AddAdornments(DWORD dwFlags = 0, LPREBARBANDINFO prbbi = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_AddAdornments(m_hWnd, ModuleHelper::GetModuleInstance(), dwFlags, prbbi); + } + + BOOL AddBands(UINT uBandCount, LPREBARBANDINFO prbbi) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_AddBands(m_hWnd, ModuleHelper::GetModuleInstance(), uBandCount, prbbi); + } + + BOOL Show(BOOL bShow = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::CommandBands_Show(m_hWnd, bShow); + } +}; + +typedef CCECommandBandsCtrlT CCECommandBandsCtrl; + +#endif // _WIN32_WCE + +}; // namespace WTL + +#endif // __ATLCTRLS_H__ diff --git a/wtl/wtl/include/atlctrlw.h b/wtl/wtl/include/atlctrlw.h new file mode 100644 index 00000000..3bf16ee5 --- /dev/null +++ b/wtl/wtl/include/atlctrlw.h @@ -0,0 +1,4161 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLCTRLW_H__ +#define __ATLCTRLW_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifdef _WIN32_WCE + #error atlctrlw.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atlctrlw.h requires atlapp.h to be included first +#endif + +#ifndef __ATLCTRLS_H__ + #error atlctrlw.h requires atlctrls.h to be included first +#endif + +#if (_WIN32_IE < 0x0400) + #error atlctrlw.h requires _WIN32_IE >= 0x0400 +#endif + +// Define _WTL_CMDBAR_VISTA_MENUS as 0 to exclude Vista menus support +#if !defined(_WTL_CMDBAR_VISTA_MENUS) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) + #define _WTL_CMDBAR_VISTA_MENUS 1 +#endif + +#if _WTL_CMDBAR_VISTA_MENUS + #if !((_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)) + #error _WTL_CMDBAR_VISTA_MENUS requires (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CCommandBarCtrlImpl +// CCommandBarCtrl +// CMDICommandBarCtrlImpl +// CMDICommandBarCtrl + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// Command Bars + +// Window Styles: +#define CBRWS_TOP CCS_TOP +#define CBRWS_BOTTOM CCS_BOTTOM +#define CBRWS_NORESIZE CCS_NORESIZE +#define CBRWS_NOPARENTALIGN CCS_NOPARENTALIGN +#define CBRWS_NODIVIDER CCS_NODIVIDER + +// Extended styles +#define CBR_EX_TRANSPARENT 0x00000001L +#define CBR_EX_SHAREMENU 0x00000002L +#define CBR_EX_ALTFOCUSMODE 0x00000004L +#define CBR_EX_TRACKALWAYS 0x00000008L +#define CBR_EX_NOVISTAMENUS 0x00000010L + +// standard command bar styles +#define ATL_SIMPLE_CMDBAR_PANE_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN) + +// Messages - support chevrons for frame windows +#define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND +#define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu +#define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu + +typedef struct tagCBRPOPUPMENU +{ + int cbSize; + HMENU hMenu; // popup menu do display + UINT uFlags; // TPM_* flags for ::TrackPopupMenuEx + int x; + int y; + LPTPMPARAMS lptpm; // ptr to TPMPARAMS for ::TrackPopupMenuEx +} CBRPOPUPMENU, *LPCBRPOPUPMENU; + +// helper class +template +class CSimpleStack : public ATL::CSimpleArray< T > +{ +public: + BOOL Push(T t) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-PUSH (%8.8X) size = %i\n"), t, GetSize()); +#endif + return Add(t); + } + + T Pop() + { + int nLast = GetSize() - 1; + if(nLast < 0) + return NULL; // must be able to convert to NULL + T t = m_aT[nLast]; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-POP (%8.8X) size = %i\n"), t, GetSize()); +#endif + if(!RemoveAt(nLast)) + return NULL; + return t; + } + + T GetCurrent() + { + int nLast = GetSize() - 1; + if(nLast < 0) + return NULL; // must be able to convert to NULL + return m_aT[nLast]; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CCommandBarCtrlBase - base class for the Command Bar implementation + +class CCommandBarCtrlBase : public CToolBarCtrl +{ +public: + struct _MsgHookData + { + HHOOK hMsgHook; + DWORD dwUsage; + + _MsgHookData() : hMsgHook(NULL), dwUsage(0) + { } + }; + + typedef ATL::CSimpleMap CMsgHookMap; + static CMsgHookMap* s_pmapMsgHook; + + static HHOOK s_hCreateHook; + static bool s_bW2K; // For animation flag + static CCommandBarCtrlBase* s_pCurrentBar; + static bool s_bStaticInit; + + CSimpleStack m_stackMenuWnd; + CSimpleStack m_stackMenuHandle; + + HWND m_hWndHook; + DWORD m_dwMagic; + + + CCommandBarCtrlBase() : m_hWndHook(NULL), m_dwMagic(1314) + { + // init static variables + if(!s_bStaticInit) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlBase::CCommandBarCtrlBase.\n")); + ATLASSERT(FALSE); + return; + } + + if(!s_bStaticInit) + { + // Just in case... + AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES); + // Animation on Win2000 only + s_bW2K = !AtlIsOldWindows(); + // done + s_bStaticInit = true; + } + + lock.Unlock(); + } + } + + bool IsCommandBarBase() const { return m_dwMagic == 1314; } +}; + +__declspec(selectany) CCommandBarCtrlBase::CMsgHookMap* CCommandBarCtrlBase::s_pmapMsgHook = NULL; +__declspec(selectany) HHOOK CCommandBarCtrlBase::s_hCreateHook = NULL; +__declspec(selectany) CCommandBarCtrlBase* CCommandBarCtrlBase::s_pCurrentBar = NULL; +__declspec(selectany) bool CCommandBarCtrlBase::s_bW2K = false; +__declspec(selectany) bool CCommandBarCtrlBase::s_bStaticInit = false; + + +/////////////////////////////////////////////////////////////////////////////// +// CCommandBarCtrl - ATL implementation of Command Bars + +template +class ATL_NO_VTABLE CCommandBarCtrlImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + +// Declarations + struct _MenuItemData // menu item data + { + DWORD dwMagic; + LPTSTR lpstrText; + UINT fType; + UINT fState; + int iButton; + + _MenuItemData() { dwMagic = 0x1313; } + bool IsCmdBarMenuItem() { return (dwMagic == 0x1313); } + }; + + struct _ToolBarData // toolbar resource data + { + WORD wVersion; + WORD wWidth; + WORD wHeight; + WORD wItemCount; + //WORD aItems[wItemCount] + + WORD* items() + { return (WORD*)(this+1); } + }; + +// Constants + enum _CmdBarDrawConstants + { + s_kcxGap = 1, + s_kcxTextMargin = 2, + s_kcxButtonMargin = 3, + s_kcyButtonMargin = 3 + }; + + enum + { + _nMaxMenuItemTextLength = 100, + _chChevronShortcut = _T('/') + }; + +#ifndef DT_HIDEPREFIX + enum { DT_HIDEPREFIX = 0x00100000 }; +#endif // !DT_HIDEPREFIX + +// Data members + HMENU m_hMenu; + HIMAGELIST m_hImageList; + ATL::CSimpleValArray m_arrCommand; + + DWORD m_dwExtendedStyle; // Command Bar specific extended styles + + ATL::CContainedWindow m_wndParent; + + bool m_bMenuActive:1; + bool m_bAttachedMenu:1; + bool m_bImagesVisible:1; + bool m_bPopupItem:1; + bool m_bContextMenu:1; + bool m_bEscapePressed:1; + bool m_bSkipMsg:1; + bool m_bParentActive:1; + bool m_bFlatMenus:1; + bool m_bUseKeyboardCues:1; + bool m_bShowKeyboardCues:1; + bool m_bAllowKeyboardCues:1; + bool m_bKeyboardInput:1; + bool m_bAlphaImages:1; + bool m_bLayoutRTL:1; + bool m_bSkipPostDown:1; + bool m_bVistaMenus:1; + + int m_nPopBtn; + int m_nNextPopBtn; + + SIZE m_szBitmap; + SIZE m_szButton; + + COLORREF m_clrMask; + CFont m_fontMenu; // used internally, only to measure text + + UINT m_uSysKey; + + HWND m_hWndFocus; // Alternate focus mode + + int m_cxExtraSpacing; + +#if _WTL_CMDBAR_VISTA_MENUS + ATL::CSimpleValArray m_arrVistaBitmap; // Bitmaps for Vista menus +#endif // _WTL_CMDBAR_VISTA_MENUS + +// Constructor/destructor + CCommandBarCtrlImpl() : + m_hMenu(NULL), + m_hImageList(NULL), + m_wndParent(this, 1), + m_bMenuActive(false), + m_bAttachedMenu(false), + m_nPopBtn(-1), + m_nNextPopBtn(-1), + m_bPopupItem(false), + m_bImagesVisible(true), + m_bSkipMsg(false), + m_uSysKey(0), + m_hWndFocus(NULL), + m_bContextMenu(false), + m_bEscapePressed(false), + m_clrMask(RGB(192, 192, 192)), + m_dwExtendedStyle(CBR_EX_TRANSPARENT | CBR_EX_SHAREMENU | CBR_EX_TRACKALWAYS), + m_bParentActive(true), + m_bFlatMenus(false), + m_bUseKeyboardCues(false), + m_bShowKeyboardCues(false), + m_bAllowKeyboardCues(true), + m_bKeyboardInput(false), + m_cxExtraSpacing(0), + m_bAlphaImages(false), + m_bLayoutRTL(false), + m_bSkipPostDown(false), + m_bVistaMenus(false) + { + SetImageSize(16, 15); // default + } + + ~CCommandBarCtrlImpl() + { + if(m_wndParent.IsWindow()) +/*scary!*/ m_wndParent.UnsubclassWindow(); + + if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0) + ::DestroyMenu(m_hMenu); + + if(m_hImageList != NULL) + ::ImageList_Destroy(m_hImageList); + } + +// Attributes + DWORD GetCommandBarExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetCommandBarExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + return dwPrevStyle; + } + + CMenuHandle GetMenu() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return m_hMenu; + } + + COLORREF GetImageMaskColor() const + { + return m_clrMask; + } + + COLORREF SetImageMaskColor(COLORREF clrMask) + { + COLORREF clrOld = m_clrMask; + m_clrMask = clrMask; + return clrOld; + } + + bool GetImagesVisible() const + { + return m_bImagesVisible; + } + + bool SetImagesVisible(bool bVisible) + { + bool bOld = m_bImagesVisible; + m_bImagesVisible = bVisible; + return bOld; + } + + void GetImageSize(SIZE& size) const + { + size = m_szBitmap; + } + + bool SetImageSize(SIZE& size) + { + return SetImageSize(size.cx, size.cy); + } + + bool SetImageSize(int cx, int cy) + { + if(m_hImageList != NULL) + { + if(::ImageList_GetImageCount(m_hImageList) == 0) // empty + { + ::ImageList_Destroy(m_hImageList); + m_hImageList = NULL; + } + else + { + return false; // can't set, image list exists + } + } + + if(cx == 0 || cy == 0) + return false; + + m_szBitmap.cx = cx; + m_szBitmap.cy = cy; + m_szButton.cx = m_szBitmap.cx + 2 * s_kcxButtonMargin; + m_szButton.cy = m_szBitmap.cy + 2 * s_kcyButtonMargin; + + return true; + } + + bool GetAlphaImages() const + { + return m_bAlphaImages; + } + + bool SetAlphaImages(bool bAlphaImages) + { + if(m_hImageList != NULL) + { + if(::ImageList_GetImageCount(m_hImageList) == 0) // empty + { + ::ImageList_Destroy(m_hImageList); + m_hImageList = NULL; + } + else + { + return false; // can't set, image list exists + } + } + + m_bAlphaImages = bAlphaImages; + return true; + } + + HWND GetCmdBar() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L); + } + +// Methods + HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + UINT nID = 0, LPVOID lpCreateParam = NULL) + { + // These styles are required for command bars + dwStyle |= TBSTYLE_LIST | TBSTYLE_FLAT; +#if (_MSC_VER >= 1300) + return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + return _baseClass::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam); +#endif // !(_MSC_VER >= 1300) + } + + BOOL AttachToWindow(HWND hWnd) + { + ATLASSERT(m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); + BOOL bRet = SubclassWindow(hWnd); + if(bRet) + { + m_bAttachedMenu = true; + T* pT = static_cast(this); + pT->GetSystemSettings(); + } + return bRet; + } + + BOOL LoadMenu(ATL::_U_STRINGorID menu) + { + ATLASSERT(::IsWindow(m_hWnd)); + + if(m_bAttachedMenu) // doesn't work in this mode + return FALSE; + if(menu.m_lpstr == NULL) + return FALSE; + + HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr); + if(hMenu == NULL) + return FALSE; + + return AttachMenu(hMenu); + } + + BOOL AttachMenu(HMENU hMenu) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hMenu == NULL || ::IsMenu(hMenu)); + if(hMenu != NULL && !::IsMenu(hMenu)) + return FALSE; + +#if _WTL_CMDBAR_VISTA_MENUS + // remove Vista bitmaps if used + if(m_bVistaMenus && (m_hMenu != NULL)) + { + T* pT = static_cast(this); + pT->_RemoveVistaBitmapsFromMenu(); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + + // destroy old menu, if needed, and set new one + if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0) + ::DestroyMenu(m_hMenu); + + m_hMenu = hMenu; + + if(m_bAttachedMenu) // Nothing else in this mode + return TRUE; + + // Build buttons according to menu + SetRedraw(FALSE); + + // Clear all buttons + int nCount = GetButtonCount(); + for(int i = 0; i < nCount; i++) + ATLVERIFY(DeleteButton(0) != FALSE); + + // Add buttons for each menu item + if(m_hMenu != NULL) + { + int nItems = ::GetMenuItemCount(m_hMenu); + + T* pT = static_cast(this); + pT; // avoid level 4 warning + TCHAR szString[pT->_nMaxMenuItemTextLength]; + for(int i = 0; i < nItems; i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU; + mii.fType = MFT_STRING; + mii.dwTypeData = szString; + mii.cch = pT->_nMaxMenuItemTextLength; + BOOL bRet = ::GetMenuItemInfo(m_hMenu, i, TRUE, &mii); + ATLASSERT(bRet); + // If we have more than the buffer, we assume we have bitmaps bits + if(lstrlen(szString) > pT->_nMaxMenuItemTextLength - 1) + { + mii.fType = MFT_BITMAP; + ::SetMenuItemInfo(m_hMenu, i, TRUE, &mii); + szString[0] = 0; + } + + // NOTE: Command Bar currently supports only drop-down menu items + ATLASSERT(mii.hSubMenu != NULL); + + TBBUTTON btn = { 0 }; + btn.iBitmap = 0; + btn.idCommand = i; + btn.fsState = (BYTE)(((mii.fState & MFS_DISABLED) == 0) ? TBSTATE_ENABLED : 0); + btn.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE | TBSTYLE_DROPDOWN; + btn.dwData = 0; + btn.iString = 0; + + bRet = InsertButton(-1, &btn); + ATLASSERT(bRet); + + TBBUTTONINFO bi = { 0 }; + bi.cbSize = sizeof(TBBUTTONINFO); + bi.dwMask = TBIF_TEXT; + bi.pszText = szString; + + bRet = SetButtonInfo(i, &bi); + ATLASSERT(bRet); + } + } + + SetRedraw(TRUE); + Invalidate(); + UpdateWindow(); + + return TRUE; + } + + BOOL LoadImages(ATL::_U_STRINGorID image) + { + return _LoadImagesHelper(image, false); + } + + BOOL LoadMappedImages(UINT nIDImage, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0) + { + return _LoadImagesHelper(nIDImage, true, nFlags , lpColorMap, nMapSize); + } + + BOOL _LoadImagesHelper(ATL::_U_STRINGorID image, bool bMapped, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + HINSTANCE hInstance = ModuleHelper::GetResourceInstance(); + + HRSRC hRsrc = ::FindResource(hInstance, image.m_lpstr, (LPTSTR)RT_TOOLBAR); + if(hRsrc == NULL) + return FALSE; + + HGLOBAL hGlobal = ::LoadResource(hInstance, hRsrc); + if(hGlobal == NULL) + return FALSE; + + _ToolBarData* pData = (_ToolBarData*)::LockResource(hGlobal); + if(pData == NULL) + return FALSE; + ATLASSERT(pData->wVersion == 1); + + WORD* pItems = pData->items(); + int nItems = pData->wItemCount; + + // Set internal data + SetImageSize(pData->wWidth, pData->wHeight); + + // Create image list if needed + if(m_hImageList == NULL) + { + // Check if the bitmap is 32-bit (alpha channel) bitmap (valid for Windows XP only) + T* pT = static_cast(this); + m_bAlphaImages = AtlIsAlphaBitmapResource(image); + + if(!pT->CreateInternalImageList(pData->wItemCount)) + return FALSE; + } + +#if _WTL_CMDBAR_VISTA_MENUS + int nOldImageCount = ::ImageList_GetImageCount(m_hImageList); +#endif // _WTL_CMDBAR_VISTA_MENUS + + // Add bitmap to our image list + CBitmap bmp; + if(bMapped) + { + ATLASSERT(HIWORD(PtrToUlong(image.m_lpstr)) == 0); // if mapped, must be a numeric ID + int nIDImage = (int)(short)LOWORD(PtrToUlong(image.m_lpstr)); + bmp.LoadMappedBitmap(nIDImage, (WORD)nFlags, lpColorMap, nMapSize); + } + else + { + if(m_bAlphaImages) + bmp = (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE); + else + bmp.LoadBitmap(image.m_lpstr); + } + ATLASSERT(bmp.m_hBitmap != NULL); + if(bmp.m_hBitmap == NULL) + return FALSE; + if(::ImageList_AddMasked(m_hImageList, bmp, m_clrMask) == -1) + return FALSE; + + // Fill the array with command IDs + for(int i = 0; i < nItems; i++) + { + if(pItems[i] != 0) + m_arrCommand.Add(pItems[i]); + } + + int nImageCount = ::ImageList_GetImageCount(m_hImageList); + ATLASSERT(nImageCount == m_arrCommand.GetSize()); + if(nImageCount != m_arrCommand.GetSize()) + return FALSE; + +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + T* pT = static_cast(this); + pT->_AddVistaBitmapsFromImageList(nOldImageCount, nImageCount - nOldImageCount); + ATLASSERT(nImageCount == m_arrVistaBitmap.GetSize()); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + + return TRUE; + } + + BOOL AddBitmap(ATL::_U_STRINGorID bitmap, int nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + CBitmap bmp; + bmp.LoadBitmap(bitmap.m_lpstr); + if(bmp.m_hBitmap == NULL) + return FALSE; + return AddBitmap(bmp, nCommandID); + } + + BOOL AddBitmap(HBITMAP hBitmap, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + // Create image list if it doesn't exist + if(m_hImageList == NULL) + { + if(!pT->CreateInternalImageList(1)) + return FALSE; + } + // check bitmap size + CBitmapHandle bmp = hBitmap; + SIZE size = { 0, 0 }; + bmp.GetSize(size); + if(size.cx != m_szBitmap.cx || size.cy != m_szBitmap.cy) + { + ATLASSERT(FALSE); // must match size! + return FALSE; + } + // add bitmap + int nRet = ::ImageList_AddMasked(m_hImageList, hBitmap, m_clrMask); + if(nRet == -1) + return FALSE; + BOOL bRet = m_arrCommand.Add((WORD)nCommandID); + ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize()); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1); + ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize()); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + return bRet; + } + + BOOL AddIcon(ATL::_U_STRINGorID icon, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); + if(hIcon == NULL) + return FALSE; + return AddIcon(hIcon, nCommandID); + } + + BOOL AddIcon(HICON hIcon, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + // create image list if it doesn't exist + if(m_hImageList == NULL) + { + if(!pT->CreateInternalImageList(1)) + return FALSE; + } + + int nRet = ::ImageList_AddIcon(m_hImageList, hIcon); + if(nRet == -1) + return FALSE; + BOOL bRet = m_arrCommand.Add((WORD)nCommandID); + ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize()); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1); + ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize()); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + return bRet; + } + + BOOL ReplaceBitmap(ATL::_U_STRINGorID bitmap, int nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + CBitmap bmp; + bmp.LoadBitmap(bitmap.m_lpstr); + if(bmp.m_hBitmap == NULL) + return FALSE; + return ReplaceBitmap(bmp, nCommandID); + } + + BOOL ReplaceBitmap(HBITMAP hBitmap, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + BOOL bRet = FALSE; + for(int i = 0; i < m_arrCommand.GetSize(); i++) + { + if(m_arrCommand[i] == nCommandID) + { + bRet = ::ImageList_Remove(m_hImageList, i); + if(bRet) + { + m_arrCommand.RemoveAt(i); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + if(m_arrVistaBitmap[i] != NULL) + ::DeleteObject(m_arrVistaBitmap[i]); + m_arrVistaBitmap.RemoveAt(i); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + } + break; + } + } + if(bRet) + bRet = AddBitmap(hBitmap, nCommandID); + return bRet; + } + + BOOL ReplaceIcon(ATL::_U_STRINGorID icon, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); + if(hIcon == NULL) + return FALSE; + return ReplaceIcon(hIcon, nCommandID); + } + + BOOL ReplaceIcon(HICON hIcon, UINT nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + BOOL bRet = FALSE; + for(int i = 0; i < m_arrCommand.GetSize(); i++) + { + if(m_arrCommand[i] == nCommandID) + { + bRet = (::ImageList_ReplaceIcon(m_hImageList, i, hIcon) != -1); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista() && bRet != FALSE) + { + T* pT = static_cast(this); + pT->_ReplaceVistaBitmapFromImageList(i); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + break; + } + } + return bRet; + } + + BOOL RemoveImage(int nCommandID) + { + ATLASSERT(::IsWindow(m_hWnd)); + + BOOL bRet = FALSE; + for(int i = 0; i < m_arrCommand.GetSize(); i++) + { + if(m_arrCommand[i] == nCommandID) + { + bRet = ::ImageList_Remove(m_hImageList, i); + if(bRet) + { + m_arrCommand.RemoveAt(i); +#if _WTL_CMDBAR_VISTA_MENUS + if(RunTimeHelper::IsVista()) + { + if(m_arrVistaBitmap[i] != NULL) + ::DeleteObject(m_arrVistaBitmap[i]); + m_arrVistaBitmap.RemoveAt(i); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + } + break; + } + } + return bRet; + } + + BOOL RemoveAllImages() + { + ATLASSERT(::IsWindow(m_hWnd)); + + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Removing all images\n")); + BOOL bRet = ::ImageList_RemoveAll(m_hImageList); + if(bRet) + { + m_arrCommand.RemoveAll(); +#if _WTL_CMDBAR_VISTA_MENUS + for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++) + { + if(m_arrVistaBitmap[i] != NULL) + ::DeleteObject(m_arrVistaBitmap[i]); + } + m_arrVistaBitmap.RemoveAll(); +#endif // _WTL_CMDBAR_VISTA_MENUS + } + return bRet; + } + + BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(::IsMenu(hMenu)); + if(!::IsMenu(hMenu)) + return FALSE; + m_bContextMenu = true; + if(m_bUseKeyboardCues) + m_bShowKeyboardCues = m_bKeyboardInput; + T* pT = static_cast(this); + return pT->DoTrackPopupMenu(hMenu, uFlags, x, y, lpParams); + } + + BOOL SetMDIClient(HWND /*hWndMDIClient*/) + { + // Use CMDICommandBarCtrl for MDI support + ATLASSERT(FALSE); + return FALSE; + } + +// Message map and handlers + BEGIN_MSG_MAP(CCommandBarCtrlImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_INITMENU, OnInitMenu) + MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) + MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) + MESSAGE_HANDLER(GetAutoPopupMessage(), OnInternalAutoPopup) + MESSAGE_HANDLER(GetGetBarMessage(), OnInternalGetBar) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + MESSAGE_HANDLER(WM_MENUCHAR, OnMenuChar) + + MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) + MESSAGE_HANDLER(WM_KEYUP, OnKeyUp) + MESSAGE_HANDLER(WM_CHAR, OnChar) + MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown) + MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp) + MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar) +// public API handlers - these stay to support chevrons in atlframe.h + MESSAGE_HANDLER(CBRM_GETMENU, OnAPIGetMenu) + MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnAPITrackPopupMenu) + MESSAGE_HANDLER(CBRM_GETCMDBAR, OnAPIGetCmdBar) + + MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) + MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem) + + MESSAGE_HANDLER(WM_FORWARDMSG, OnForwardMsg) + ALT_MSG_MAP(1) // Parent window messages + NOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE, OnParentHotItemChange) + NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentDropDown) + MESSAGE_HANDLER(WM_INITMENUPOPUP, OnParentInitMenuPopup) + MESSAGE_HANDLER(GetGetBarMessage(), OnParentInternalGetBar) + MESSAGE_HANDLER(WM_SYSCOMMAND, OnParentSysCommand) + MESSAGE_HANDLER(CBRM_GETMENU, OnParentAPIGetMenu) + MESSAGE_HANDLER(WM_MENUCHAR, OnParentMenuChar) + MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnParentAPITrackPopupMenu) + MESSAGE_HANDLER(CBRM_GETCMDBAR, OnParentAPIGetCmdBar) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnParentSettingChange) + + MESSAGE_HANDLER(WM_DRAWITEM, OnParentDrawItem) + MESSAGE_HANDLER(WM_MEASUREITEM, OnParentMeasureItem) + + MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate) + NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnParentCustomDraw) + ALT_MSG_MAP(2) // MDI client window messages + // Use CMDICommandBarCtrl for MDI support + ALT_MSG_MAP(3) // Message hook messages + MESSAGE_HANDLER(WM_MOUSEMOVE, OnHookMouseMove) + MESSAGE_HANDLER(WM_SYSKEYDOWN, OnHookSysKeyDown) + MESSAGE_HANDLER(WM_SYSKEYUP, OnHookSysKeyUp) + MESSAGE_HANDLER(WM_SYSCHAR, OnHookSysChar) + MESSAGE_HANDLER(WM_KEYDOWN, OnHookKeyDown) + MESSAGE_HANDLER(WM_NEXTMENU, OnHookNextMenu) + MESSAGE_HANDLER(WM_CHAR, OnHookChar) + END_MSG_MAP() + + LRESULT OnForwardMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + LPMSG pMsg = (LPMSG)lParam; + if(pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST) + m_bKeyboardInput = false; + else if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) + m_bKeyboardInput = true; + LRESULT lRet = 0; + ProcessWindowMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam, lRet, 3); + return lRet; + } + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + // Let the toolbar initialize itself + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + // get and use system settings + T* pT = static_cast(this); + pT->GetSystemSettings(); + // Parent init + ATL::CWindow wndParent = GetParent(); + ATL::CWindow wndTopLevelParent = wndParent.GetTopLevelParent(); + m_wndParent.SubclassWindow(wndTopLevelParent); + // Toolbar Init + SetButtonStructSize(); + SetImageList(NULL); + + // Create message hook if needed + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnCreate.\n")); + ATLASSERT(FALSE); + return -1; + } + + if(s_pmapMsgHook == NULL) + { + ATLTRY(s_pmapMsgHook = new CMsgHookMap); + ATLASSERT(s_pmapMsgHook != NULL); + } + + if(s_pmapMsgHook != NULL) + { + DWORD dwThreadID = ::GetCurrentThreadId(); + _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID); + if(pData == NULL) + { + ATLTRY(pData = new _MsgHookData); + ATLASSERT(pData != NULL); + HHOOK hMsgHook = ::SetWindowsHookEx(WH_GETMESSAGE, MessageHookProc, ModuleHelper::GetModuleInstance(), dwThreadID); + ATLASSERT(hMsgHook != NULL); + if(pData != NULL && hMsgHook != NULL) + { + pData->hMsgHook = hMsgHook; + pData->dwUsage = 1; + BOOL bRet = s_pmapMsgHook->Add(dwThreadID, pData); + bRet; + ATLASSERT(bRet); + } + } + else + { + (pData->dwUsage)++; + } + } + lock.Unlock(); + + // Get layout +#if (WINVER >= 0x0500) + m_bLayoutRTL = ((GetExStyle() & WS_EX_LAYOUTRTL) != 0); +#endif // (WINVER >= 0x0500) + + return lRet; + } + + LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + +#if _WTL_CMDBAR_VISTA_MENUS + if(m_bVistaMenus && (m_hMenu != NULL)) + { + T* pT = static_cast(this); + pT->_RemoveVistaBitmapsFromMenu(); + } + + for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++) + { + if(m_arrVistaBitmap[i] != NULL) + ::DeleteObject(m_arrVistaBitmap[i]); + } +#endif // _WTL_CMDBAR_VISTA_MENUS + + if(m_bAttachedMenu) // nothing to do in this mode + return lRet; + + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnDestroy.\n")); + ATLASSERT(FALSE); + return lRet; + } + + if(s_pmapMsgHook != NULL) + { + DWORD dwThreadID = ::GetCurrentThreadId(); + _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID); + if(pData != NULL) + { + (pData->dwUsage)--; + if(pData->dwUsage == 0) + { + BOOL bRet = ::UnhookWindowsHookEx(pData->hMsgHook); + ATLASSERT(bRet); + bRet = s_pmapMsgHook->Remove(dwThreadID); + ATLASSERT(bRet); + if(bRet) + delete pData; + } + + if(s_pmapMsgHook->GetSize() == 0) + { + delete s_pmapMsgHook; + s_pmapMsgHook = NULL; + } + } + } + + lock.Unlock(); + + return lRet; + } + + LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyDown\n")); +#endif + bHandled = FALSE; + // Simulate Alt+Space for the parent + if(wParam == VK_SPACE) + { + m_wndParent.PostMessage(WM_SYSKEYDOWN, wParam, lParam | (1 << 29)); + bHandled = TRUE; + } +#if (_WIN32_IE >= 0x0500) + else if(wParam == VK_LEFT || wParam == VK_RIGHT) + { + WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT; + + if(!m_bMenuActive) + { + T* pT = static_cast(this); + int nBtn = GetHotItem(); + int nNextBtn = (wParam == wpNext) ? pT->GetNextMenuItem(nBtn) : pT->GetPreviousMenuItem(nBtn); + if(nNextBtn == -2) + { + SetHotItem(-1); + if(pT->DisplayChevronMenu()) + bHandled = TRUE; + } + } + } +#endif // (_WIN32_IE >= 0x0500) + return 0; + } + + LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyUp\n")); +#endif + if(wParam != VK_SPACE) + bHandled = FALSE; + return 0; + } + + LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnChar\n")); +#endif + if(wParam != VK_SPACE) + bHandled = FALSE; + else + return 0; + // Security + if(!m_wndParent.IsWindowEnabled() || ::GetFocus() != m_hWnd) + return 0; + + // Handle mnemonic press when we have focus + int nBtn = 0; + if(wParam != VK_RETURN && !MapAccelerator((TCHAR)LOWORD(wParam), nBtn)) + { +#if (_WIN32_IE >= 0x0500) + if((TCHAR)LOWORD(wParam) != _chChevronShortcut) +#endif // (_WIN32_IE >= 0x0500) + ::MessageBeep(0); + } + else + { +#if (_WIN32_IE >= 0x0500) + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcBtn = { 0 }; + GetItemRect(nBtn, &rcBtn); + TBBUTTON tbb = { 0 }; + GetButton(nBtn, &tbb); + if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right) + { +#endif // (_WIN32_IE >= 0x0500) + PostMessage(WM_KEYDOWN, VK_DOWN, 0L); + if(wParam != VK_RETURN) + SetHotItem(nBtn); +#if (_WIN32_IE >= 0x0500) + } + else + { + ::MessageBeep(0); + bHandled = TRUE; + } +#endif // (_WIN32_IE >= 0x0500) + } + return 0; + } + + LRESULT OnSysKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyDown\n")); +#endif + bHandled = FALSE; + return 0; + } + + LRESULT OnSysKeyUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyUp\n")); +#endif + bHandled = FALSE; + return 0; + } + + LRESULT OnSysChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysChar\n")); +#endif + bHandled = FALSE; + return 0; + } + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bAttachedMenu || (m_dwExtendedStyle & CBR_EX_TRANSPARENT)) + { + bHandled = FALSE; + return 0; + } + + CDCHandle dc = (HDC)wParam; + RECT rect = { 0 }; + GetClientRect(&rect); + dc.FillRect(&rect, COLOR_MENU); + + return 1; // don't do the default erase + } + + LRESULT OnInitMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + int nIndex = GetHotItem(); + SendMessage(WM_MENUSELECT, MAKEWPARAM(nIndex, MF_POPUP|MF_HILITE), (LPARAM)m_hMenu); + bHandled = FALSE; + return 1; + } + + LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if((BOOL)HIWORD(lParam)) // System menu, do nothing + { + bHandled = FALSE; + return 1; + } + + if(!(m_bAttachedMenu || m_bMenuActive)) // Not attached or ours, do nothing + { + bHandled = FALSE; + return 1; + } + +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnInitMenuPopup\n")); +#endif + // forward to the parent or subclassed window, so it can handle update UI + LRESULT lRet = 0; + if(m_bAttachedMenu) + lRet = DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem()); + else + lRet = m_wndParent.DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem()); + +#if _WTL_CMDBAR_VISTA_MENUS + // If Vista menus are active, just set bitmaps and return + if(m_bVistaMenus) + { + CMenuHandle menu = (HMENU)wParam; + ATLASSERT(menu.m_hMenu != NULL); + + for(int i = 0; i < menu.GetMenuItemCount(); i++) + { + WORD nID = (WORD)menu.GetMenuItemID(i); + int nIndex = m_arrCommand.Find(nID); + + CMenuItemInfo mii; + mii.fMask = MIIM_BITMAP; + mii.hbmpItem = (m_bImagesVisible && (nIndex != -1)) ? m_arrVistaBitmap[nIndex] : NULL; + menu.SetMenuItemInfo(i, TRUE, &mii); + } + + return lRet; + } +#endif // _WTL_CMDBAR_VISTA_MENUS + + // Convert menu items to ownerdraw, add our data + if(m_bImagesVisible) + { + CMenuHandle menuPopup = (HMENU)wParam; + ATLASSERT(menuPopup.m_hMenu != NULL); + + T* pT = static_cast(this); + pT; // avoid level 4 warning + TCHAR szString[pT->_nMaxMenuItemTextLength]; + BOOL bRet = FALSE; + for(int i = 0; i < menuPopup.GetMenuItemCount(); i++) + { + CMenuItemInfo mii; + mii.cch = pT->_nMaxMenuItemTextLength; + mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; + mii.dwTypeData = szString; + bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + if(!(mii.fType & MFT_OWNERDRAW)) // Not already an ownerdraw item + { + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; + _MenuItemData* pMI = NULL; + ATLTRY(pMI = new _MenuItemData); + ATLASSERT(pMI != NULL); + if(pMI != NULL) + { + pMI->fType = mii.fType; + pMI->fState = mii.fState; + mii.fType |= MFT_OWNERDRAW; + pMI->iButton = -1; + for(int j = 0; j < m_arrCommand.GetSize(); j++) + { + if(m_arrCommand[j] == mii.wID) + { + pMI->iButton = j; + break; + } + } + int cchLen = lstrlen(szString) + 1; + pMI->lpstrText = NULL; + ATLTRY(pMI->lpstrText = new TCHAR[cchLen]); + ATLASSERT(pMI->lpstrText != NULL); + if(pMI->lpstrText != NULL) + SecureHelper::strcpy_x(pMI->lpstrText, cchLen, szString); + mii.dwItemData = (ULONG_PTR)pMI; + bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + } + } + } + + // Add it to the list + m_stackMenuHandle.Push(menuPopup.m_hMenu); + } + + return lRet; + } + + LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if(!m_bAttachedMenu) // Not attached, do nothing, forward to parent + { + m_bPopupItem = (lParam != NULL) && ((HMENU)lParam != m_hMenu) && (HIWORD(wParam) & MF_POPUP); + if(m_wndParent.IsWindow()) + m_wndParent.SendMessage(uMsg, wParam, lParam); + bHandled = FALSE; + return 1; + } + + // Check if a menu is closing, do a cleanup + if(HIWORD(wParam) == 0xFFFF && lParam == NULL) // Menu closing + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuSelect - CLOSING!!!!\n")); +#endif + ATLASSERT(m_stackMenuWnd.GetSize() == 0); + // Restore the menu items to the previous state for all menus that were converted + if(m_bImagesVisible) + { + HMENU hMenu = NULL; + while((hMenu = m_stackMenuHandle.Pop()) != NULL) + { + CMenuHandle menuPopup = hMenu; + ATLASSERT(menuPopup.m_hMenu != NULL); + // Restore state and delete menu item data + BOOL bRet = FALSE; + for(int i = 0; i < menuPopup.GetMenuItemCount(); i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_DATA | MIIM_TYPE; + bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData; + if(pMI != NULL && pMI->IsCmdBarMenuItem()) + { + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; + mii.fType = pMI->fType; + mii.dwTypeData = pMI->lpstrText; + mii.cch = lstrlen(pMI->lpstrText); + mii.dwItemData = NULL; + + bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + delete [] pMI->lpstrText; + pMI->dwMagic = 0x6666; + delete pMI; + } + } + } + } + } + + bHandled = FALSE; + return 1; + } + + LRESULT OnInternalAutoPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + int nIndex = (int)wParam; + T* pT = static_cast(this); + pT->DoPopupMenu(nIndex, false); + return 0; + } + + LRESULT OnInternalGetBar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + // Let's make sure we're not embedded in another process + if((LPVOID)wParam != NULL) + *((DWORD*)wParam) = GetCurrentProcessId(); + if(IsWindowVisible()) + return (LRESULT)static_cast(this); + else + return NULL; + } + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { +#ifndef SPI_GETKEYBOARDCUES + const UINT SPI_SETKEYBOARDCUES = 0x100B; +#endif // !SPI_GETKEYBOARDCUES +#ifndef SPI_GETFLATMENU + const UINT SPI_SETFLATMENU = 0x1023; +#endif // !SPI_GETFLATMENU + + if(wParam == SPI_SETNONCLIENTMETRICS || wParam == SPI_SETKEYBOARDCUES || wParam == SPI_SETFLATMENU) + { + T* pT = static_cast(this); + pT->GetSystemSettings(); + } + + return 0; + } + + LRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + + LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam; + int cyMin = ::GetSystemMetrics(SM_CYMENU); + if(lpWP->cy < cyMin) + lpWP->cy = cyMin; + + return lRet; + } + + LRESULT OnMenuChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuChar\n")); +#endif + bHandled = TRUE; + T* pT = static_cast(this); + + LRESULT lRet; + if(m_bMenuActive && LOWORD(wParam) != 0x0D) + lRet = 0; + else + lRet = MAKELRESULT(1, 1); + + if(m_bMenuActive && HIWORD(wParam) == MF_POPUP) + { + // Convert character to lower/uppercase and possibly Unicode, using current keyboard layout + TCHAR ch = (TCHAR)LOWORD(wParam); + CMenuHandle menu = (HMENU)lParam; + int nCount = ::GetMenuItemCount(menu); + int nRetCode = MNC_EXECUTE; + BOOL bRet = FALSE; + TCHAR szString[pT->_nMaxMenuItemTextLength]; + WORD wMnem = 0; + bool bFound = false; + for(int i = 0; i < nCount; i++) + { + CMenuItemInfo mii; + mii.cch = pT->_nMaxMenuItemTextLength; + mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; + mii.dwTypeData = szString; + bRet = menu.GetMenuItemInfo(i, TRUE, &mii); + if(!bRet || (mii.fType & MFT_SEPARATOR)) + continue; + _MenuItemData* pmd = (_MenuItemData*)mii.dwItemData; + if(pmd != NULL && pmd->IsCmdBarMenuItem()) + { + LPTSTR p = pmd->lpstrText; + + if(p != NULL) + { + while(*p && *p != _T('&')) + p = ::CharNext(p); + if(p != NULL && *p) + { + DWORD dwP = MAKELONG(*(++p), 0); + DWORD dwC = MAKELONG(ch, 0); + if(::CharLower((LPTSTR)ULongToPtr(dwP)) == ::CharLower((LPTSTR)ULongToPtr(dwC))) + { + if(!bFound) + { + wMnem = (WORD)i; + bFound = true; + } + else + { + nRetCode = MNC_SELECT; + break; + } + } + } + } + } + } + if(bFound) + { + if(nRetCode == MNC_EXECUTE) + { + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + pT->GiveFocusBack(); + } + bHandled = TRUE; + lRet = MAKELRESULT(wMnem, nRetCode); + } + } + else if(!m_bMenuActive) + { + int nBtn = 0; + if(!MapAccelerator((TCHAR)LOWORD(wParam), nBtn)) + { + bHandled = FALSE; + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + pT->GiveFocusBack(); + +#if (_WIN32_IE >= 0x0500) + // check if we should display chevron menu + if((TCHAR)LOWORD(wParam) == pT->_chChevronShortcut) + { + if(pT->DisplayChevronMenu()) + bHandled = TRUE; + } +#endif // (_WIN32_IE >= 0x0500) + } + else if(m_wndParent.IsWindowEnabled()) + { +#if (_WIN32_IE >= 0x0500) + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcBtn = { 0 }; + GetItemRect(nBtn, &rcBtn); + TBBUTTON tbb = { 0 }; + GetButton(nBtn, &tbb); + if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right) + { +#endif // (_WIN32_IE >= 0x0500) + if(m_bUseKeyboardCues && !m_bShowKeyboardCues) + { + m_bAllowKeyboardCues = true; + ShowKeyboardCues(true); + } + pT->TakeFocus(); + PostMessage(WM_KEYDOWN, VK_DOWN, 0L); + SetHotItem(nBtn); +#if (_WIN32_IE >= 0x0500) + } + else + { + ::MessageBeep(0); + } +#endif // (_WIN32_IE >= 0x0500) + } + } + + return lRet; + } + + LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + LPDRAWITEMSTRUCT lpDrawItemStruct = (LPDRAWITEMSTRUCT)lParam; + _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData; + if(lpDrawItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem()) + { + T* pT = static_cast(this); + pT->DrawItem(lpDrawItemStruct); + } + else + { + bHandled = FALSE; + } + return (LRESULT)TRUE; + } + + LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + LPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT)lParam; + _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData; + if(lpMeasureItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem()) + { + T* pT = static_cast(this); + pT->MeasureItem(lpMeasureItemStruct); + } + else + { + bHandled = FALSE; + } + return (LRESULT)TRUE; + } + +// API message handlers + LRESULT OnAPIGetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)m_hMenu; + } + + LRESULT OnAPITrackPopupMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + if(lParam == NULL) + return FALSE; + LPCBRPOPUPMENU lpCBRPopupMenu = (LPCBRPOPUPMENU)lParam; + if(lpCBRPopupMenu->cbSize != sizeof(CBRPOPUPMENU)) + return FALSE; + + T* pT = static_cast(this); + return pT->TrackPopupMenu(lpCBRPopupMenu->hMenu, lpCBRPopupMenu->uFlags, lpCBRPopupMenu->x, lpCBRPopupMenu->y, lpCBRPopupMenu->lptpm); + } + + LRESULT OnAPIGetCmdBar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)m_hWnd; + } + +// Parent window message handlers + LRESULT OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + LPNMTBHOTITEM lpNMHT = (LPNMTBHOTITEM)pnmh; + + // Check if this comes from us + if(pnmh->hwndFrom != m_hWnd) + { + bHandled = FALSE; + return 0; + } + + bool bBlockTracking = false; + if((m_dwExtendedStyle & CBR_EX_TRACKALWAYS) == 0) + { + DWORD dwProcessID; + ::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID); + bBlockTracking = (::GetCurrentProcessId() != dwProcessID); + } + + if((!m_wndParent.IsWindowEnabled() || bBlockTracking) && (lpNMHT->dwFlags & HICF_MOUSE)) + { + return 1; + } + else + { +#ifndef HICF_LMOUSE + const DWORD HICF_LMOUSE = 0x00000080; // left mouse button selected +#endif + bHandled = FALSE; + + // Send WM_MENUSELECT to the app if it needs to display a status text + if(!(lpNMHT->dwFlags & HICF_MOUSE) + && !(lpNMHT->dwFlags & HICF_ACCELERATOR) + && !(lpNMHT->dwFlags & HICF_LMOUSE)) + { + if(lpNMHT->dwFlags & HICF_ENTERING) + m_wndParent.SendMessage(WM_MENUSELECT, 0, (LPARAM)m_hMenu); + if(lpNMHT->dwFlags & HICF_LEAVING) + m_wndParent.SendMessage(WM_MENUSELECT, MAKEWPARAM(0, 0xFFFF), NULL); + } + + return 0; + } + } + + LRESULT OnParentDropDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + // Check if this comes from us + if(pnmh->hwndFrom != m_hWnd) + { + bHandled = FALSE; + return 1; + } + + T* pT = static_cast(this); + if(::GetFocus() != m_hWnd) + pT->TakeFocus(); + LPNMTOOLBAR pNMToolBar = (LPNMTOOLBAR)pnmh; + int nIndex = CommandToIndex(pNMToolBar->iItem); + m_bContextMenu = false; + m_bEscapePressed = false; + pT->DoPopupMenu(nIndex, true); + + return TBDDRET_DEFAULT; + } + + LRESULT OnParentInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnInitMenuPopup(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentInternalGetBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnInternalGetBar(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; + if((m_uSysKey == VK_MENU + || (m_uSysKey == VK_F10 && !(::GetKeyState(VK_SHIFT) & 0x80)) + || m_uSysKey == VK_SPACE) + && wParam == SC_KEYMENU) + { + T* pT = static_cast(this); + if(::GetFocus() == m_hWnd) + { + pT->GiveFocusBack(); // exit menu "loop" + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + } + else if(m_uSysKey != VK_SPACE && !m_bSkipMsg) + { + if(m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues) + ShowKeyboardCues(true); + + pT->TakeFocus(); // enter menu "loop" + bHandled = TRUE; + } + else if(m_uSysKey != VK_SPACE) + { + bHandled = TRUE; + } + } + m_bSkipMsg = false; + return 0; + } + + LRESULT OnParentAPIGetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnAPIGetMenu(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentMenuChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnMenuChar(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentAPITrackPopupMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnAPITrackPopupMenu(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentAPIGetCmdBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnAPIGetCmdBar(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + OnSettingChange(uMsg, wParam, lParam, bHandled); + bHandled = FALSE; + return 1; + } + + LRESULT OnParentDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnDrawItem(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + return OnMeasureItem(uMsg, wParam, lParam, bHandled); + } + + LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + m_bParentActive = (LOWORD(wParam) != WA_INACTIVE); + if(!m_bParentActive && m_bUseKeyboardCues && m_bShowKeyboardCues) + { + ShowKeyboardCues(false); // this will repaint our window + } + else + { + Invalidate(); + UpdateWindow(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnParentCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + LRESULT lRet = CDRF_DODEFAULT; + bHandled = FALSE; + if(pnmh->hwndFrom == m_hWnd) + { + LPNMTBCUSTOMDRAW lpTBCustomDraw = (LPNMTBCUSTOMDRAW)pnmh; + if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT) + { + lRet = CDRF_NOTIFYITEMDRAW; + bHandled = TRUE; + } + else if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) + { + if(m_bFlatMenus) + { +#ifndef COLOR_MENUHILIGHT + const int COLOR_MENUHILIGHT = 29; +#endif // !COLOR_MENUHILIGHT + bool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED); + if(!bDisabled && ((lpTBCustomDraw->nmcd.uItemState & CDIS_HOT) == CDIS_HOT || + (lpTBCustomDraw->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED)) + { + ::FillRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_MENUHILIGHT)); + ::FrameRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_HIGHLIGHT)); + lpTBCustomDraw->clrText = ::GetSysColor(m_bParentActive ? COLOR_HIGHLIGHTTEXT : COLOR_GRAYTEXT); + } + else if(bDisabled || !m_bParentActive) + { + lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT); + } + CDCHandle dc = lpTBCustomDraw->nmcd.hdc; + dc.SetTextColor(lpTBCustomDraw->clrText); + dc.SetBkMode(lpTBCustomDraw->nStringBkMode); + HFONT hFont = GetFont(); + HFONT hFontOld = NULL; + if(hFont != NULL) + hFontOld = dc.SelectFont(hFont); + const int cchText = 200; + TCHAR szText[cchText] = { 0 }; + TBBUTTONINFO tbbi = { 0 }; + tbbi.cbSize = sizeof(TBBUTTONINFO); + tbbi.dwMask = TBIF_TEXT; + tbbi.pszText = szText; + tbbi.cchText = cchText; + GetButtonInfo((int)lpTBCustomDraw->nmcd.dwItemSpec, &tbbi); + dc.DrawText(szText, -1, &lpTBCustomDraw->nmcd.rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); + if(hFont != NULL) + dc.SelectFont(hFontOld); + lRet = CDRF_SKIPDEFAULT; + bHandled = TRUE; + } + else if(!m_bParentActive) + { + lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT); + bHandled = TRUE; + } + } + } + return lRet; + } + +// Message hook handlers + LRESULT OnHookMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + static POINT s_point = { -1, -1 }; + DWORD dwPoint = ::GetMessagePos(); + POINT point = { GET_X_LPARAM(dwPoint), GET_Y_LPARAM(dwPoint) }; + + bHandled = FALSE; + if(m_bMenuActive) + { + if(::WindowFromPoint(point) == m_hWnd) + { + ScreenToClient(&point); + int nHit = HitTest(&point); + + if((point.x != s_point.x || point.y != s_point.y) && nHit >= 0 && nHit < ::GetMenuItemCount(m_hMenu) && nHit != m_nPopBtn && m_nPopBtn != -1) + { + TBBUTTON tbb = { 0 }; + GetButton(nHit, &tbb); + if((tbb.fsState & TBSTATE_ENABLED) != 0) + { + m_nNextPopBtn = nHit | 0xFFFF0000; + HWND hWndMenu = m_stackMenuWnd.GetCurrent(); + ATLASSERT(hWndMenu != NULL); + + // this one is needed to close a menu if mouse button was down + ::PostMessage(hWndMenu, WM_LBUTTONUP, 0, MAKELPARAM(point.x, point.y)); + // this one closes a popup menu + ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L); + + bHandled = TRUE; + } + } + } + } + else + { + ScreenToClient(&point); + } + + s_point = point; + return 0; + } + + LRESULT OnHookSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYDOWN (0x%2.2X)\n"), wParam); +#endif + + if(wParam == VK_MENU && m_bParentActive && m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues) + ShowKeyboardCues(true); + + if(wParam != VK_SPACE && !m_bMenuActive && ::GetFocus() == m_hWnd) + { + m_bAllowKeyboardCues = false; + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + T* pT = static_cast(this); + pT->GiveFocusBack(); + m_bSkipMsg = true; + } + else + { + if(wParam == VK_SPACE && m_bUseKeyboardCues && m_bShowKeyboardCues) + { + m_bAllowKeyboardCues = true; + ShowKeyboardCues(false); + } + m_uSysKey = (UINT)wParam; + } + return 0; + } + + LRESULT OnHookSysKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(!m_bAllowKeyboardCues) + m_bAllowKeyboardCues = true; + bHandled = FALSE; + wParam; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYUP (0x%2.2X)\n"), wParam); +#endif + return 0; + } + + LRESULT OnHookSysChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSCHAR (0x%2.2X)\n"), wParam); +#endif + + if(!m_bMenuActive && m_hWndHook != m_hWnd && wParam != VK_SPACE) + bHandled = TRUE; + return 0; + } + + LRESULT OnHookKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_KEYDOWN (0x%2.2X)\n"), wParam); +#endif + bHandled = FALSE; + T* pT = static_cast(this); + + if(wParam == VK_ESCAPE && m_stackMenuWnd.GetSize() <= 1) + { + if(m_bMenuActive && !m_bContextMenu) + { + int nHot = GetHotItem(); + if(nHot == -1) + nHot = m_nPopBtn; + if(nHot == -1) + nHot = 0; + SetHotItem(nHot); + bHandled = TRUE; + pT->TakeFocus(); + m_bEscapePressed = true; // To keep focus + m_bSkipPostDown = false; + } + else if(::GetFocus() == m_hWnd && m_wndParent.IsWindow()) + { + SetHotItem(-1); + pT->GiveFocusBack(); + bHandled = TRUE; + } + } + else if(wParam == VK_RETURN || wParam == VK_UP || wParam == VK_DOWN) + { + if(!m_bMenuActive && ::GetFocus() == m_hWnd && m_wndParent.IsWindow()) + { + int nHot = GetHotItem(); + if(nHot != -1) + { + if(wParam != VK_RETURN) + { + if(!m_bSkipPostDown) + { +// IE4 only: WM_KEYDOWN doesn't generate TBN_DROPDOWN, we need to simulate a mouse click +#if (_WIN32_IE < 0x0500) + DWORD dwMajor = 0, dwMinor = 0; + ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); + if(dwMajor <= 4 || (dwMajor == 5 && dwMinor < 80)) + { + RECT rect; + GetItemRect(nHot, &rect); + PostMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(rect.left, rect.top)); + } +#endif // (_WIN32_IE < 0x0500) + PostMessage(WM_KEYDOWN, VK_DOWN, 0L); + m_bSkipPostDown = true; + } + else + { + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - skipping posting another VK_DOWN\n")); + m_bSkipPostDown = false; + } + } + } + else + { + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Can't find hot button\n")); + } + } + if(wParam == VK_RETURN && m_bMenuActive) + { + PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); + m_nNextPopBtn = -1; + pT->GiveFocusBack(); + } + } + else if(wParam == VK_LEFT || wParam == VK_RIGHT) + { + WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT; + WPARAM wpPrev = m_bLayoutRTL ? VK_RIGHT : VK_LEFT; + + if(m_bMenuActive && !m_bContextMenu && !(wParam == wpNext && m_bPopupItem)) + { + bool bAction = false; + if(wParam == wpPrev && s_pCurrentBar->m_stackMenuWnd.GetSize() == 1) + { + m_nNextPopBtn = pT->GetPreviousMenuItem(m_nPopBtn); + if(m_nNextPopBtn != -1) + bAction = true; + } + else if(wParam == wpNext) + { + m_nNextPopBtn = pT->GetNextMenuItem(m_nPopBtn); + if(m_nNextPopBtn != -1) + bAction = true; + } + HWND hWndMenu = m_stackMenuWnd.GetCurrent(); + ATLASSERT(hWndMenu != NULL); + + // Close the popup menu + if(bAction) + { + ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L); + if(wParam == wpNext) + { + int cItem = m_stackMenuWnd.GetSize() - 1; + while(cItem >= 0) + { + hWndMenu = m_stackMenuWnd[cItem]; + if(hWndMenu != NULL) + ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L); + cItem--; + } + } +#if (_WIN32_IE >= 0x0500) + if(m_nNextPopBtn == -2) + { + m_nNextPopBtn = -1; + pT->DisplayChevronMenu(); + } +#endif // (_WIN32_IE >= 0x0500) + bHandled = TRUE; + } + } + } + return 0; + } + + LRESULT OnHookNextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_NEXTMENU\n")); +#endif + bHandled = FALSE; + return 1; + } + + LRESULT OnHookChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_CHAR (0x%2.2X)\n"), wParam); +#endif + bHandled = (wParam == VK_ESCAPE); + return 0; + } + +// Implementation - ownerdraw overrideables and helpers + void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) + { + T* pT = static_cast(this); + if(m_bFlatMenus) + pT->DrawItemFlat(lpDrawItemStruct); + else + pT->DrawItem3D(lpDrawItemStruct); + + } + + void DrawItem3D(LPDRAWITEMSTRUCT lpDrawItemStruct) + { + _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData; + CDCHandle dc = lpDrawItemStruct->hDC; + const RECT& rcItem = lpDrawItemStruct->rcItem; + T* pT = static_cast(this); + + if(pmd->fType & MFT_SEPARATOR) + { + // draw separator + RECT rc = rcItem; + rc.top += (rc.bottom - rc.top) / 2; // vertical center + dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line + } + else // not a separator + { + BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED; + BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED; + BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED; + BOOL bHasImage = FALSE; + + if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1) + bSelected = FALSE; + RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect + ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically + + int iButton = pmd->iButton; + if(iButton >= 0) + { + bHasImage = TRUE; + + // calc drawing point + SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy }; + sz.cx /= 2; + sz.cy /= 2; + POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy }; + + // fill background depending on state + if(!bChecked || (bSelected && !bDisabled)) + { + if(!bDisabled) + dc.FillRect(&rcButn, (bChecked && !bSelected) ? COLOR_3DLIGHT : COLOR_MENU); + else + dc.FillRect(&rcButn, COLOR_MENU); + } + else + { + COLORREF crTxt = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE)); + COLORREF crBk = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT)); + CBrush hbr(CDCHandle::GetHalftoneBrush()); + dc.SetBrushOrg(rcButn.left, rcButn.top); + dc.FillRect(&rcButn, hbr); + dc.SetTextColor(crTxt); + dc.SetBkColor(crBk); + } + + // draw disabled or normal + if(!bDisabled) + { + // draw pushed-in or popped-out edge + if(bSelected || bChecked) + { + RECT rc2 = rcButn; + dc.DrawEdge(&rc2, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER, BF_RECT); + } + // draw the image + ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT); + } + else + { + HBRUSH hBrushBackground = bChecked ? NULL : ::GetSysColorBrush(COLOR_MENU); + pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground); + } + } + else + { + // no image - look for custom checked/unchecked bitmaps + CMenuItemInfo info; + info.fMask = MIIM_CHECKMARKS | MIIM_TYPE; + ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info); + if(bChecked || info.hbmpUnchecked != NULL) + { + BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0); + bHasImage = pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked); + } + } + + // draw item text + int cxButn = m_szButton.cx; + COLORREF colorBG = ::GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_MENU); + if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT) + { + RECT rcBG = rcItem; + if(bHasImage) + rcBG.left += cxButn + s_kcxGap; + dc.FillRect(&rcBG, bSelected ? COLOR_HIGHLIGHT : COLOR_MENU); + } + + // calc text rectangle and colors + RECT rcText = rcItem; + rcText.left += cxButn + s_kcxGap + s_kcxTextMargin; + rcText.right -= cxButn; + dc.SetBkMode(TRANSPARENT); + COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)); + + // font already selected by Windows + if(bDisabled && (!bSelected || colorText == colorBG)) + { + // disabled - draw shadow text shifted down and right 1 pixel (unles selected) + RECT rcDisabled = rcText; + ::OffsetRect(&rcDisabled, 1, 1); + pT->DrawMenuText(dc, rcDisabled, pmd->lpstrText, ::GetSysColor(COLOR_3DHILIGHT)); + } + pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally! + } + } + + void DrawItemFlat(LPDRAWITEMSTRUCT lpDrawItemStruct) + { + _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData; + CDCHandle dc = lpDrawItemStruct->hDC; + const RECT& rcItem = lpDrawItemStruct->rcItem; + T* pT = static_cast(this); + +#ifndef COLOR_MENUHILIGHT + const int COLOR_MENUHILIGHT = 29; +#endif // !COLOR_MENUHILIGHT + + BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED; + BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED; + BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED; + + // paint background + if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT) + { + if(bSelected) + { + dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENUHILIGHT)); + dc.FrameRect(&rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHT)); + } + else + { + dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENU)); + } + } + + if(pmd->fType & MFT_SEPARATOR) + { + // draw separator + RECT rc = rcItem; + rc.top += (rc.bottom - rc.top) / 2; // vertical center + dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line + } + else // not a separator + { + if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1) + bSelected = FALSE; + RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect + ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically + + // draw background and border for checked items + if(bChecked) + { + RECT rcCheck = rcButn; + ::InflateRect(&rcCheck, -1, -1); + if(bSelected) + dc.FillRect(&rcCheck, ::GetSysColorBrush(COLOR_MENU)); + dc.FrameRect(&rcCheck, ::GetSysColorBrush(COLOR_HIGHLIGHT)); + } + + int iButton = pmd->iButton; + if(iButton >= 0) + { + // calc drawing point + SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy }; + sz.cx /= 2; + sz.cy /= 2; + POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy }; + + // draw disabled or normal + if(!bDisabled) + { + ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT); + } + else + { + HBRUSH hBrushBackground = ::GetSysColorBrush((bSelected && !(bDisabled && bChecked)) ? COLOR_MENUHILIGHT : COLOR_MENU); + HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW); + pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground, hBrushBackground, hBrushDisabledImage); + } + } + else + { + // no image - look for custom checked/unchecked bitmaps + CMenuItemInfo info; + info.fMask = MIIM_CHECKMARKS | MIIM_TYPE; + ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info); + if(bChecked || info.hbmpUnchecked != NULL) + { + BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0); + pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked); + } + } + + // draw item text + int cxButn = m_szButton.cx; + // calc text rectangle and colors + RECT rcText = rcItem; + rcText.left += cxButn + s_kcxGap + s_kcxTextMargin; + rcText.right -= cxButn; + dc.SetBkMode(TRANSPARENT); + COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)); + + pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally! + } + } + + void DrawMenuText(CDCHandle& dc, RECT& rc, LPCTSTR lpstrText, COLORREF color) + { + int nTab = -1; + for(int i = 0; i < lstrlen(lpstrText); i++) + { + if(lpstrText[i] == _T('\t')) + { + nTab = i; + break; + } + } + dc.SetTextColor(color); + dc.DrawText(lpstrText, nTab, &rc, DT_SINGLELINE | DT_LEFT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); + if(nTab != -1) + dc.DrawText(&lpstrText[nTab + 1], -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); + } + + void DrawBitmapDisabled(CDCHandle& dc, int nImage, POINT point, + HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE), + HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT), + HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW)) + { +#if (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) + if(m_bAlphaImages) + { + IMAGELISTDRAWPARAMS ildp = { 0 }; + ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS); + ildp.himl = m_hImageList; + ildp.i = nImage; + ildp.hdcDst = dc; + ildp.x = point.x; + ildp.y = point.y; + ildp.cx = 0; + ildp.cy = 0; + ildp.xBitmap = 0; + ildp.yBitmap = 0; + ildp.fStyle = ILD_TRANSPARENT; + ildp.fState = ILS_SATURATE; + ildp.Frame = 0; + ::ImageList_DrawIndirect(&ildp); + } + else +#endif // (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) + { + // create memory DC + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + // create mono or color bitmap + CBitmap bmp; + bmp.CreateCompatibleBitmap(dc, m_szBitmap.cx, m_szBitmap.cy); + ATLASSERT(bmp.m_hBitmap != NULL); + // draw image into memory DC--fill BG white first + HBITMAP hBmpOld = dcMem.SelectBitmap(bmp); + dcMem.PatBlt(0, 0, m_szBitmap.cx, m_szBitmap.cy, WHITENESS); + // If white is the text color, we can't use the normal painting since + // it would blend with the WHITENESS, but the mask is OK + UINT uDrawStyle = (::GetSysColor(COLOR_BTNTEXT) == RGB(255, 255, 255)) ? ILD_MASK : ILD_NORMAL; + ::ImageList_Draw(m_hImageList, nImage, dcMem, 0, 0, uDrawStyle); + dc.DitherBlt(point.x, point.y, m_szBitmap.cx, m_szBitmap.cy, dcMem, NULL, 0, 0, hBrushBackground, hBrush3DEffect, hBrushDisabledImage); + dcMem.SelectBitmap(hBmpOld); // restore + } + } + + // old name + BOOL Draw3DCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck) + { + return DrawCheckmark(dc, rc, bSelected, bDisabled, bRadio, hBmpCheck); + } + + BOOL DrawCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck) + { + // get checkmark bitmap, if none, use Windows standard + SIZE size = { 0, 0 }; + CBitmapHandle bmp = hBmpCheck; + if(hBmpCheck != NULL) + { + bmp.GetSize(size); + } + else + { + size.cx = ::GetSystemMetrics(SM_CXMENUCHECK); + size.cy = ::GetSystemMetrics(SM_CYMENUCHECK); + bmp.CreateCompatibleBitmap(dc, size.cx, size.cy); + ATLASSERT(bmp.m_hBitmap != NULL); + } + // center bitmap in caller's rectangle + RECT rcDest = rc; + if((rc.right - rc.left) > size.cx) + { + rcDest.left = rc.left + (rc.right - rc.left - size.cx) / 2; + rcDest.right = rcDest.left + size.cx; + } + if((rc.bottom - rc.top) > size.cy) + { + rcDest.top = rc.top + (rc.bottom - rc.top - size.cy) / 2; + rcDest.bottom = rcDest.top + size.cy; + } + // paint background + if(!m_bFlatMenus) + { + if(bSelected && !bDisabled) + { + dc.FillRect(&rcDest, COLOR_MENU); + } + else + { + COLORREF clrTextOld = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE)); + COLORREF clrBkOld = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT)); + CBrush hbr(CDCHandle::GetHalftoneBrush()); + dc.SetBrushOrg(rcDest.left, rcDest.top); + dc.FillRect(&rcDest, hbr); + dc.SetTextColor(clrTextOld); + dc.SetBkColor(clrBkOld); + } + } + + // create source image + CDC dcSource; + dcSource.CreateCompatibleDC(dc); + HBITMAP hBmpOld = dcSource.SelectBitmap(bmp); + // set colors + const COLORREF clrBlack = RGB(0, 0, 0); + const COLORREF clrWhite = RGB(255, 255, 255); + COLORREF clrTextOld = dc.SetTextColor(clrBlack); + COLORREF clrBkOld = dc.SetBkColor(clrWhite); + // create mask + CDC dcMask; + dcMask.CreateCompatibleDC(dc); + CBitmap bmpMask; + bmpMask.CreateBitmap(size.cx, size.cy, 1, 1, NULL); + HBITMAP hBmpOld1 = dcMask.SelectBitmap(bmpMask); + + // draw the checkmark transparently + int cx = rcDest.right - rcDest.left; + int cy = rcDest.bottom - rcDest.top; + if(hBmpCheck != NULL) + { + // build mask based on transparent color + dcSource.SetBkColor(m_clrMask); + dcMask.SetBkColor(clrBlack); + dcMask.SetTextColor(clrWhite); + dcMask.BitBlt(0, 0, size.cx, size.cy, dcSource, 0, 0, SRCCOPY); + // draw bitmap using the mask + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT); + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, SRCAND); + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT); + } + else + { + const DWORD ROP_DSno = 0x00BB0226L; + const DWORD ROP_DSa = 0x008800C6L; + const DWORD ROP_DSo = 0x00EE0086L; + const DWORD ROP_DSna = 0x00220326L; + + // draw mask + RECT rcSource = { 0, 0, min(size.cx, rc.right - rc.left), min(size.cy, rc.bottom - rc.top) }; + dcMask.DrawFrameControl(&rcSource, DFC_MENU, bRadio ? DFCS_MENUBULLET : DFCS_MENUCHECK); + + // draw shadow if disabled + if(!m_bFlatMenus && bDisabled) + { + // offset by one pixel + int x = rcDest.left + 1; + int y = rcDest.top + 1; + // paint source bitmap + const int nColor = COLOR_3DHILIGHT; + dcSource.FillRect(&rcSource, nColor); + // draw checkmark - special case black and white colors + COLORREF clrCheck = ::GetSysColor(nColor); + if(clrCheck == clrWhite) + { + dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSno); + dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSa); + } + else + { + if(clrCheck != clrBlack) + { + ATLASSERT(dcSource.GetTextColor() == clrBlack); + ATLASSERT(dcSource.GetBkColor() == clrWhite); + dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna); + } + dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSa); + dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSo); + } + } + + // paint source bitmap + const int nColor = bDisabled ? COLOR_BTNSHADOW : COLOR_MENUTEXT; + dcSource.FillRect(&rcSource, nColor); + // draw checkmark - special case black and white colors + COLORREF clrCheck = ::GetSysColor(nColor); + if(clrCheck == clrWhite) + { + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSno); + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSa); + } + else + { + if(clrCheck != clrBlack) + { + ATLASSERT(dcSource.GetTextColor() == clrBlack); + ATLASSERT(dcSource.GetBkColor() == clrWhite); + dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna); + } + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSa); + dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSo); + } + } + // restore all + dc.SetTextColor(clrTextOld); + dc.SetBkColor(clrBkOld); + dcSource.SelectBitmap(hBmpOld); + dcMask.SelectBitmap(hBmpOld1); + if(hBmpCheck == NULL) + bmp.DeleteObject(); + // draw pushed-in hilight + if(!m_bFlatMenus && !bDisabled) + { + if(rc.right - rc.left > size.cx) + ::InflateRect(&rcDest, 1,1); // inflate checkmark by one pixel all around + dc.DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT); + } + + return TRUE; + } + + void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) + { + _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData; + + if(pmd->fType & MFT_SEPARATOR) // separator - use half system height and zero width + { + lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 2; + lpMeasureItemStruct->itemWidth = 0; + } + else + { + // compute size of text - use DrawText with DT_CALCRECT + CWindowDC dc(NULL); + CFont fontBold; + HFONT hOldFont = NULL; + if(pmd->fState & MFS_DEFAULT) + { + // need bold version of font + LOGFONT lf = { 0 }; + m_fontMenu.GetLogFont(lf); + lf.lfWeight += 200; + fontBold.CreateFontIndirect(&lf); + ATLASSERT(fontBold.m_hFont != NULL); + hOldFont = dc.SelectFont(fontBold); + } + else + { + hOldFont = dc.SelectFont(m_fontMenu); + } + + RECT rcText = { 0, 0, 0, 0 }; + dc.DrawText(pmd->lpstrText, -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); + int cx = rcText.right - rcText.left; + dc.SelectFont(hOldFont); + + LOGFONT lf = { 0 }; + m_fontMenu.GetLogFont(lf); + int cy = lf.lfHeight; + if(cy < 0) + cy = -cy; + const int cyMargin = 8; + cy += cyMargin; + + // height of item is the bigger of these two + lpMeasureItemStruct->itemHeight = max(cy, (int)m_szButton.cy); + + // width is width of text plus a bunch of stuff + cx += 2 * s_kcxTextMargin; // L/R margin for readability + cx += s_kcxGap; // space between button and menu text + cx += 2 * m_szButton.cx; // button width (L=button; R=empty margin) + cx += m_cxExtraSpacing; // extra between item text and accelerator keys + + // Windows adds 1 to returned value + cx -= ::GetSystemMetrics(SM_CXMENUCHECK) - 1; + lpMeasureItemStruct->itemWidth = cx; // done deal + } + } + +// Implementation - Hook procs + static LRESULT CALLBACK CreateHookProc(int nCode, WPARAM wParam, LPARAM lParam) + { + const int cchClassName = 7; + TCHAR szClassName[cchClassName] = { 0 }; + + if(nCode == HCBT_CREATEWND) + { + HWND hWndMenu = (HWND)wParam; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_CREATEWND (HWND = %8.8X)\n"), hWndMenu); +#endif + + ::GetClassName(hWndMenu, szClassName, cchClassName); + if(!lstrcmp(_T("#32768"), szClassName)) + s_pCurrentBar->m_stackMenuWnd.Push(hWndMenu); + } + else if(nCode == HCBT_DESTROYWND) + { + HWND hWndMenu = (HWND)wParam; +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_DESTROYWND (HWND = %8.8X)\n"), hWndMenu); +#endif + + ::GetClassName(hWndMenu, szClassName, cchClassName); + if(!lstrcmp(_T("#32768"), szClassName)) + { + ATLASSERT(hWndMenu == s_pCurrentBar->m_stackMenuWnd.GetCurrent()); + s_pCurrentBar->m_stackMenuWnd.Pop(); + } + } + + return ::CallNextHookEx(s_hCreateHook, nCode, wParam, lParam); + } + + static LRESULT CALLBACK MessageHookProc(int nCode, WPARAM wParam, LPARAM lParam) + { + LPMSG pMsg = (LPMSG)lParam; + + if(nCode == HC_ACTION && wParam == PM_REMOVE && pMsg->message != GetGetBarMessage() && pMsg->message != WM_FORWARDMSG) + { + CCommandBarCtrlBase* pCmdBar = NULL; + HWND hWnd = pMsg->hwnd; + DWORD dwPID = 0; + while(pCmdBar == NULL && hWnd != NULL) + { + pCmdBar = (CCommandBarCtrlBase*)::SendMessage(hWnd, GetGetBarMessage(), (WPARAM)&dwPID, 0L); + hWnd = ::GetParent(hWnd); + } + + if(pCmdBar != NULL && dwPID == GetCurrentProcessId()) + { + pCmdBar->m_hWndHook = pMsg->hwnd; + ATLASSERT(pCmdBar->IsCommandBarBase()); + + if(::IsWindow(pCmdBar->m_hWnd)) + pCmdBar->SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg); + else + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook skipping message, can't find command bar!\n")); + } + } + + LRESULT lRet = 0; + ATLASSERT(s_pmapMsgHook != NULL); + if(s_pmapMsgHook != NULL) + { + DWORD dwThreadID = ::GetCurrentThreadId(); + _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID); + if(pData != NULL) + { + lRet = ::CallNextHookEx(pData->hMsgHook, nCode, wParam, lParam); + } + } + return lRet; + } + +// Implementation + void DoPopupMenu(int nIndex, bool bAnimate) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - DoPopupMenu, bAnimate = %s\n"), bAnimate ? "true" : "false"); +#endif + + // Menu animation flags +#ifndef TPM_VERPOSANIMATION + const UINT TPM_VERPOSANIMATION = 0x1000L; +#endif +#ifndef TPM_NOANIMATION + const UINT TPM_NOANIMATION = 0x4000L; +#endif + T* pT = static_cast(this); + + // get popup menu and it's position + RECT rect = { 0 }; + GetItemRect(nIndex, &rect); + POINT pt = { rect.left, rect.bottom }; + MapWindowPoints(NULL, &pt, 1); + MapWindowPoints(NULL, &rect); + TPMPARAMS TPMParams = { 0 }; + TPMParams.cbSize = sizeof(TPMPARAMS); + TPMParams.rcExclude = rect; + HMENU hMenuPopup = ::GetSubMenu(m_hMenu, nIndex); + ATLASSERT(hMenuPopup != NULL); + + // get button ID + TBBUTTON tbb = { 0 }; + GetButton(nIndex, &tbb); + int nCmdID = tbb.idCommand; + + m_nPopBtn = nIndex; // remember current button's index + + // press button and display popup menu + PressButton(nCmdID, TRUE); + SetHotItem(nCmdID); + pT->DoTrackPopupMenu(hMenuPopup, TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | + (s_bW2K ? (bAnimate ? TPM_VERPOSANIMATION : TPM_NOANIMATION) : 0), pt.x, pt.y, &TPMParams); + PressButton(nCmdID, FALSE); + if(::GetFocus() != m_hWnd) + SetHotItem(-1); + + m_nPopBtn = -1; // restore + + // eat next message if click is on the same button + MSG msg = { 0 }; + if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rect, msg.pt)) + ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE); + + // check if another popup menu should be displayed + if(m_nNextPopBtn != -1) + { + PostMessage(GetAutoPopupMessage(), m_nNextPopBtn & 0xFFFF); + if(!(m_nNextPopBtn & 0xFFFF0000) && !m_bPopupItem) + PostMessage(WM_KEYDOWN, VK_DOWN, 0); + m_nNextPopBtn = -1; + } + else + { + m_bContextMenu = false; + // If user didn't hit escape, give focus back + if(!m_bEscapePressed) + { + if(m_bUseKeyboardCues && m_bShowKeyboardCues) + m_bAllowKeyboardCues = false; + pT->GiveFocusBack(); + } + else + { + SetHotItem(nCmdID); + SetAnchorHighlight(TRUE); + } + } + } + + BOOL DoTrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL) + { + CMenuHandle menuPopup = hMenu; + + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::DoTrackPopupMenu.\n")); + ATLASSERT(FALSE); + return FALSE; + } + + ATLASSERT(s_hCreateHook == NULL); + + s_pCurrentBar = static_cast(this); + + s_hCreateHook = ::SetWindowsHookEx(WH_CBT, CreateHookProc, ModuleHelper::GetModuleInstance(), GetCurrentThreadId()); + ATLASSERT(s_hCreateHook != NULL); + + m_bPopupItem = false; + m_bMenuActive = true; + + BOOL bTrackRet = menuPopup.TrackPopupMenuEx(uFlags, x, y, m_hWnd, lpParams); + m_bMenuActive = false; + + ::UnhookWindowsHookEx(s_hCreateHook); + + s_hCreateHook = NULL; + s_pCurrentBar = NULL; + + lock.Unlock(); + + // cleanup - convert menus back to original state +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - TrackPopupMenu - cleanup\n")); +#endif + + ATLASSERT(m_stackMenuWnd.GetSize() == 0); + + UpdateWindow(); + ATL::CWindow wndTL = GetTopLevelParent(); + wndTL.UpdateWindow(); + + // restore the menu items to the previous state for all menus that were converted + if(m_bImagesVisible) + { + HMENU hMenuSav = NULL; + while((hMenuSav = m_stackMenuHandle.Pop()) != NULL) + { + menuPopup = hMenuSav; + BOOL bRet = FALSE; + // restore state and delete menu item data + for(int i = 0; i < menuPopup.GetMenuItemCount(); i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID; + bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData; + if(pMI != NULL && pMI->IsCmdBarMenuItem()) + { + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; + mii.fType = pMI->fType; + mii.fState = pMI->fState; + mii.dwTypeData = pMI->lpstrText; + mii.cch = lstrlen(pMI->lpstrText); + mii.dwItemData = NULL; + + bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); + // this one triggers WM_MEASUREITEM + menuPopup.ModifyMenu(i, MF_BYPOSITION | mii.fType | mii.fState, mii.wID, pMI->lpstrText); + ATLASSERT(bRet); + + delete [] pMI->lpstrText; + delete pMI; + } + } + } + } + return bTrackRet; + } + + int GetPreviousMenuItem(int nBtn) const + { + if(nBtn == -1) + return -1; +#if (_WIN32_IE >= 0x0500) + RECT rcClient; + GetClientRect(&rcClient); +#endif // (_WIN32_IE >= 0x0500) + int nNextBtn; + for(nNextBtn = nBtn - 1; nNextBtn != nBtn; nNextBtn--) + { + if(nNextBtn < 0) + nNextBtn = ::GetMenuItemCount(m_hMenu) - 1; + TBBUTTON tbb = { 0 }; + GetButton(nNextBtn, &tbb); +#if (_WIN32_IE >= 0x0500) + RECT rcBtn; + GetItemRect(nNextBtn, &rcBtn); + if(rcBtn.right > rcClient.right) + { + nNextBtn = -2; // chevron + break; + } +#endif // (_WIN32_IE >= 0x0500) + if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0) + break; + } + return (nNextBtn != nBtn) ? nNextBtn : -1; + } + + int GetNextMenuItem(int nBtn) const + { + if(nBtn == -1) + return -1; +#if (_WIN32_IE >= 0x0500) + RECT rcClient = { 0 }; + GetClientRect(&rcClient); +#endif // (_WIN32_IE >= 0x0500) + int nNextBtn = 0; + int nCount = ::GetMenuItemCount(m_hMenu); + for(nNextBtn = nBtn + 1; nNextBtn != nBtn; nNextBtn++) + { + if(nNextBtn >= nCount) + nNextBtn = 0; + TBBUTTON tbb = { 0 }; + GetButton(nNextBtn, &tbb); +#if (_WIN32_IE >= 0x0500) + RECT rcBtn = { 0 }; + GetItemRect(nNextBtn, &rcBtn); + if(rcBtn.right > rcClient.right) + { + nNextBtn = -2; // chevron + break; + } +#endif // (_WIN32_IE >= 0x0500) + if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0) + break; + } + return (nNextBtn != nBtn) ? nNextBtn : -1; + } + +#if (_WIN32_IE >= 0x0500) + bool DisplayChevronMenu() + { + // assume we are in a rebar + HWND hWndReBar = GetParent(); + int nCount = (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L); + bool bRet = false; + for(int i = 0; i < nCount; i++) + { + REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_STYLE }; + BOOL bRetBandInfo = (BOOL)::SendMessage(hWndReBar, RB_GETBANDINFO, i, (LPARAM)&rbbi); + if(bRetBandInfo && rbbi.hwndChild == m_hWnd) + { + if((rbbi.fStyle & RBBS_USECHEVRON) != 0) + { + ::PostMessage(hWndReBar, RB_PUSHCHEVRON, i, 0L); + PostMessage(WM_KEYDOWN, VK_DOWN, 0L); + bRet = true; + } + break; + } + } + return bRet; + } +#endif // (_WIN32_IE >= 0x0500) + + void GetSystemSettings() + { + // refresh our font + NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0); + ATLASSERT(bRet); + if(bRet) + { + LOGFONT logfont = { 0 }; + if(m_fontMenu.m_hFont != NULL) + m_fontMenu.GetLogFont(logfont); + if(logfont.lfHeight != info.lfMenuFont.lfHeight || + logfont.lfWidth != info.lfMenuFont.lfWidth || + logfont.lfEscapement != info.lfMenuFont.lfEscapement || + logfont.lfOrientation != info.lfMenuFont.lfOrientation || + logfont.lfWeight != info.lfMenuFont.lfWeight || + logfont.lfItalic != info.lfMenuFont.lfItalic || + logfont.lfUnderline != info.lfMenuFont.lfUnderline || + logfont.lfStrikeOut != info.lfMenuFont.lfStrikeOut || + logfont.lfCharSet != info.lfMenuFont.lfCharSet || + logfont.lfOutPrecision != info.lfMenuFont.lfOutPrecision || + logfont.lfClipPrecision != info.lfMenuFont.lfClipPrecision || + logfont.lfQuality != info.lfMenuFont.lfQuality || + logfont.lfPitchAndFamily != info.lfMenuFont.lfPitchAndFamily || + lstrcmp(logfont.lfFaceName, info.lfMenuFont.lfFaceName) != 0) + { + HFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont); + ATLASSERT(hFontMenu != NULL); + if(hFontMenu != NULL) + { + if(m_fontMenu.m_hFont != NULL) + m_fontMenu.DeleteObject(); + m_fontMenu.Attach(hFontMenu); + SetFont(m_fontMenu); + AddStrings(_T("NS\0")); // for proper item height + AutoSize(); + } + } + } + + // check if we need extra spacing for menu item text + CWindowDC dc(m_hWnd); + HFONT hFontOld = dc.SelectFont(m_fontMenu); + RECT rcText = { 0, 0, 0, 0 }; + dc.DrawText(_T("\t"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); + if((rcText.right - rcText.left) < 4) + { + ::SetRectEmpty(&rcText); + dc.DrawText(_T("x"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); + m_cxExtraSpacing = rcText.right - rcText.left; + } + else + { + m_cxExtraSpacing = 0; + } + dc.SelectFont(hFontOld); + + // get Windows version + OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; + ::GetVersionEx(&ovi); + + // query keyboard cues mode (Windows 2000 or later) + if(ovi.dwMajorVersion >= 5) + { +#ifndef SPI_GETKEYBOARDCUES + const UINT SPI_GETKEYBOARDCUES = 0x100A; +#endif // !SPI_GETKEYBOARDCUES + BOOL bRetVal = TRUE; + bRet = ::SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &bRetVal, 0); + m_bUseKeyboardCues = (bRet && !bRetVal); + m_bAllowKeyboardCues = true; + ShowKeyboardCues(!m_bUseKeyboardCues); + } + + // query flat menu mode (Windows XP or later) + if((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5)) + { +#ifndef SPI_GETFLATMENU + const UINT SPI_GETFLATMENU = 0x1022; +#endif // !SPI_GETFLATMENU + BOOL bRetVal = FALSE; + bRet = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &bRetVal, 0); + m_bFlatMenus = (bRet && bRetVal); + } + +#if _WTL_CMDBAR_VISTA_MENUS + // check if we should use Vista menus + bool bVistaMenus = (RunTimeHelper::IsVista() && RunTimeHelper::IsCommCtrl6() && ((m_dwExtendedStyle & CBR_EX_NOVISTAMENUS) == 0)); + + if(bVistaMenus) + { + HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); + if(hThemeDLL != NULL) + { + typedef BOOL (STDAPICALLTYPE *PFN_IsThemeActive)(); + PFN_IsThemeActive pfnIsThemeActive = (PFN_IsThemeActive)::GetProcAddress(hThemeDLL, "IsThemeActive"); + ATLASSERT(pfnIsThemeActive != NULL); + bVistaMenus = bVistaMenus && (pfnIsThemeActive != NULL) && (pfnIsThemeActive() != FALSE); + + typedef BOOL (STDAPICALLTYPE *PFN_IsAppThemed)(); + PFN_IsAppThemed pfnIsAppThemed = (PFN_IsAppThemed)::GetProcAddress(hThemeDLL, "IsAppThemed"); + ATLASSERT(pfnIsAppThemed != NULL); + bVistaMenus = bVistaMenus && (pfnIsAppThemed != NULL) && (pfnIsAppThemed() != FALSE); + + ::FreeLibrary(hThemeDLL); + } + } + + if(!bVistaMenus && m_bVistaMenus && (m_hMenu != NULL) && (m_arrCommand.GetSize() > 0)) + { + T* pT = static_cast(this); + pT->_RemoveVistaBitmapsFromMenu(); + } + + m_bVistaMenus = bVistaMenus; +#endif // _WTL_CMDBAR_VISTA_MENUS + +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("CmdBar - GetSystemSettings:\n m_bFlatMenus = %s\n m_bUseKeyboardCues = %s m_bVistaMenus = %s\n"), + m_bFlatMenus ? "true" : "false", m_bUseKeyboardCues ? "true" : "false", m_bVistaMenus ? "true" : "false"); +#endif + } + +// Implementation - alternate focus mode support + void TakeFocus() + { + if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_hWndFocus == NULL) + m_hWndFocus = ::GetFocus(); + SetFocus(); + } + + void GiveFocusBack() + { + if(m_bParentActive) + { + if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && ::IsWindow(m_hWndFocus)) + ::SetFocus(m_hWndFocus); + else if(!(m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_wndParent.IsWindow()) + m_wndParent.SetFocus(); + } + m_hWndFocus = NULL; + SetAnchorHighlight(FALSE); + if(m_bUseKeyboardCues && m_bShowKeyboardCues) + ShowKeyboardCues(false); + m_bSkipPostDown = false; + } + + void ShowKeyboardCues(bool bShow) + { + m_bShowKeyboardCues = bShow; + SetDrawTextFlags(DT_HIDEPREFIX, m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX); + Invalidate(); + UpdateWindow(); + } + +// Implementation - internal message helpers + static UINT GetAutoPopupMessage() + { + static UINT uAutoPopupMessage = 0; + if(uAutoPopupMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetAutoPopupMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uAutoPopupMessage == 0) + uAutoPopupMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalAutoPopupMsg")); + + lock.Unlock(); + } + ATLASSERT(uAutoPopupMessage != 0); + return uAutoPopupMessage; + } + + static UINT GetGetBarMessage() + { + static UINT uGetBarMessage = 0; + if(uGetBarMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetGetBarMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uGetBarMessage == 0) + uGetBarMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalGetBarMsg")); + + lock.Unlock(); + } + ATLASSERT(uGetBarMessage != 0); + return uGetBarMessage; + } + +// Implementation + bool CreateInternalImageList(int cImages) + { + UINT uFlags = (m_bAlphaImages ? ILC_COLOR32 : ILC_COLOR24) | ILC_MASK; + m_hImageList = ::ImageList_Create(m_szBitmap.cx, m_szBitmap.cy, uFlags, cImages, 1); + ATLASSERT(m_hImageList != NULL); + return (m_hImageList != NULL); + } + +// Implementation - support for Vista menus +#if _WTL_CMDBAR_VISTA_MENUS + void _AddVistaBitmapsFromImageList(int nStartIndex, int nCount) + { + // Create display compatible memory DC + HDC hDC = ::GetDC(NULL); + CDC dcMem; + dcMem.CreateCompatibleDC(hDC); + HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); + + T* pT = static_cast(this); + // Create bitmaps for all menu items + for(int i = 0; i < nCount; i++) + { + HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nStartIndex + i, hDC, dcMem); + dcMem.SelectBitmap(hBitmapSave); + m_arrVistaBitmap.Add(hBitmap); + } + } + + void _AddVistaBitmapFromImageList(int nIndex) + { + // Create display compatible memory DC + HDC hDC = ::GetDC(NULL); + CDC dcMem; + dcMem.CreateCompatibleDC(hDC); + HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); + + // Create bitmap for menu item + T* pT = static_cast(this); + HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, hDC, dcMem); + + // Select saved bitmap back and add bitmap to the array + dcMem.SelectBitmap(hBitmapSave); + m_arrVistaBitmap.Add(hBitmap); + } + + void _ReplaceVistaBitmapFromImageList(int nIndex) + { + // Delete existing bitmap + if(m_arrVistaBitmap[nIndex] != NULL) + ::DeleteObject(m_arrVistaBitmap[nIndex]); + + // Create display compatible memory DC + HDC hDC = ::GetDC(NULL); + CDC dcMem; + dcMem.CreateCompatibleDC(hDC); + HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); + + // Create bitmap for menu item + T* pT = static_cast(this); + HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, hDC, dcMem); + + // Select saved bitmap back and replace bitmap in the array + dcMem.SelectBitmap(hBitmapSave); + m_arrVistaBitmap.SetAtIndex(nIndex, hBitmap); + } + + HBITMAP _CreateVistaBitmapHelper(int nIndex, HDC hDCSource, HDC hDCTarget) + { + // Create 32-bit bitmap + BITMAPINFO bi = { 0 }; + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = m_szBitmap.cx; + bi.bmiHeader.biHeight = m_szBitmap.cy; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + bi.bmiHeader.biSizeImage = 0; + bi.bmiHeader.biXPelsPerMeter = 0; + bi.bmiHeader.biYPelsPerMeter = 0; + bi.bmiHeader.biClrUsed = 0; + bi.bmiHeader.biClrImportant = 0; + HBITMAP hBitmap = ::CreateDIBSection(hDCSource, &bi, DIB_RGB_COLORS, NULL, NULL, 0); + ATLASSERT(hBitmap != NULL); + + // Select bitmap into target DC and draw from image list to it + if(hBitmap != NULL) + { + ::SelectObject(hDCTarget, hBitmap); + + IMAGELISTDRAWPARAMS ildp = { 0 }; + ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS); + ildp.himl = m_hImageList; + ildp.i = nIndex; + ildp.hdcDst = hDCTarget; + ildp.x = 0; + ildp.y = 0; + ildp.cx = 0; + ildp.cy = 0; + ildp.xBitmap = 0; + ildp.yBitmap = 0; + ildp.fStyle = ILD_TRANSPARENT; + ildp.fState = ILS_ALPHA; + ildp.Frame = 255; + ::ImageList_DrawIndirect(&ildp); + } + + return hBitmap; + } + + void _RemoveVistaBitmapsFromMenu() + { + CMenuHandle menu = m_hMenu; + for(int i = 0; i < m_arrCommand.GetSize(); i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_BITMAP; + mii.hbmpItem = NULL; + menu.SetMenuItemInfo(m_arrCommand[i], FALSE, &mii); + } + } +#endif // _WTL_CMDBAR_VISTA_MENUS +}; + + +class CCommandBarCtrl : public CCommandBarCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_CommandBar"), GetWndClassName()) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CMDICommandBarCtrl - ATL implementation of Command Bars for MDI apps + +template +class ATL_NO_VTABLE CMDICommandBarCtrlImpl : public CCommandBarCtrlImpl< T, TBase, TWinTraits> +{ +public: +// Data members + ATL::CContainedWindow m_wndMDIClient; + bool m_bChildMaximized; + HWND m_hWndChildMaximized; + HICON m_hIconChildMaximized; + int m_nBtnPressed; + int m_nBtnWasPressed; + + int m_cxyOffset; // offset between nonclient elements + int m_cxIconWidth; // small icon width + int m_cyIconHeight; // small icon height + int m_cxBtnWidth; // nonclient button width + int m_cyBtnHeight; // nonclient button height + int m_cxLeft; // left nonclient area width + int m_cxRight; // right nonclient area width + +// Theme declarations and data members +#ifndef _WTL_NO_AUTO_THEME +#ifndef _UXTHEME_H_ + typedef HANDLE HTHEME; +#endif // !_UXTHEME_H_ + typedef HTHEME (STDAPICALLTYPE *PFN_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList); + typedef HRESULT (STDAPICALLTYPE *PFN_CloseThemeData)(HTHEME hTheme); + typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect); + typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeParentBackground)(HWND hwnd, HDC hdc, OPTIONAL RECT* prc); + + HMODULE m_hThemeDLL; + HTHEME m_hTheme; + PFN_DrawThemeBackground m_pfnDrawThemeBackground; + PFN_DrawThemeParentBackground m_pfnDrawThemeParentBackground; +#endif // !_WTL_NO_AUTO_THEME + +// Constructor/destructor + CMDICommandBarCtrlImpl() : + m_wndMDIClient(this, 2), m_bChildMaximized(false), + m_hWndChildMaximized(NULL), m_hIconChildMaximized(NULL), + m_nBtnPressed(-1), m_nBtnWasPressed(-1), +#ifndef _WTL_NO_AUTO_THEME + m_hThemeDLL(NULL), m_hTheme(NULL), m_pfnDrawThemeBackground(NULL), m_pfnDrawThemeParentBackground(NULL), +#endif // !_WTL_NO_AUTO_THEME + m_cxyOffset(2), + m_cxIconWidth(16), m_cyIconHeight(16), + m_cxBtnWidth(16), m_cyBtnHeight(14), + m_cxLeft(20), m_cxRight(55) + { } + + ~CMDICommandBarCtrlImpl() + { + if(m_wndMDIClient.IsWindow()) +/*scary!*/ m_wndMDIClient.UnsubclassWindow(); + } + +// Operations + BOOL SetMDIClient(HWND hWndMDIClient) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(::IsWindow(hWndMDIClient)); + if(!::IsWindow(hWndMDIClient)) + return FALSE; + +#ifdef _DEBUG + // BLOCK: Test if the passed window is MDICLIENT + { + LPCTSTR lpszMDIClientClass = _T("MDICLIENT"); + const int nNameLen = 9 + 1; // "MDICLIENT" + NULL + TCHAR szClassName[nNameLen] = { 0 }; + ::GetClassName(hWndMDIClient, szClassName, nNameLen); + ATLASSERT(lstrcmpi(szClassName, lpszMDIClientClass) == 0); + } +#endif // _DEBUG + + if(m_wndMDIClient.IsWindow()) +/*scary!*/ m_wndMDIClient.UnsubclassWindow(); + + return m_wndMDIClient.SubclassWindow(hWndMDIClient); + } + +// Message maps + typedef CCommandBarCtrlImpl< T, TBase, TWinTraits > _baseClass; + BEGIN_MSG_MAP(CMDICommandBarCtrlImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) +#ifndef _WTL_NO_AUTO_THEME + MESSAGE_HANDLER(_GetThemeChangedMsg(), OnThemeChanged) +#endif // !_WTL_NO_AUTO_THEME + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize) + MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) + MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) + MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) + CHAIN_MSG_MAP(_baseClass) + ALT_MSG_MAP(1) // Parent window messages + MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate) + CHAIN_MSG_MAP_ALT(_baseClass, 1) + ALT_MSG_MAP(2) // MDI client window messages + MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu) + // no chaining needed since this was moved from the base class here + ALT_MSG_MAP(3) // Message hook messages + MESSAGE_RANGE_HANDLER(0, 0xFFFF, OnAllHookMessages) + CHAIN_MSG_MAP_ALT(_baseClass, 3) + END_MSG_MAP() + +// Additional MDI message handlers + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT lRet = _baseClass::OnCreate(uMsg, wParam, lParam, bHandled); + if(lRet == (LRESULT)-1) + return lRet; + +#ifndef _WTL_NO_AUTO_THEME + // this will fail if theming is not supported + m_hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); + if(m_hThemeDLL != NULL) + { + m_pfnDrawThemeBackground = (PFN_DrawThemeBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeBackground"); + ATLASSERT(m_pfnDrawThemeBackground != NULL); + if(m_pfnDrawThemeBackground != NULL) + { + T* pT = static_cast(this); + pT->_OpenThemeData(); + } + else + { + ::FreeLibrary(m_hThemeDLL); + m_hThemeDLL = NULL; + } + m_pfnDrawThemeParentBackground = (PFN_DrawThemeParentBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeParentBackground"); + ATLASSERT(m_pfnDrawThemeParentBackground != NULL); + } +#endif // !_WTL_NO_AUTO_THEME + + return lRet; + } + + LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + LRESULT lRet = _baseClass::OnDestroy(uMsg, wParam, lParam, bHandled); + +#ifndef _WTL_NO_AUTO_THEME + if(m_hThemeDLL != NULL) + { + T* pT = static_cast(this); + pT->_CloseThemeData(); + ::FreeLibrary(m_hThemeDLL); + m_hThemeDLL = NULL; + } +#endif // !_WTL_NO_AUTO_THEME + + return lRet; + } + +#ifndef _WTL_NO_AUTO_THEME + LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_hThemeDLL != NULL) + { + T* pT = static_cast(this); + pT->_CloseThemeData(); + pT->_OpenThemeData(); + } + return 0; + } +#endif // !_WTL_NO_AUTO_THEME + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + T* pT = static_cast(this); + pT->_AdjustBtnSize(GET_Y_LPARAM(lParam)); + return lRet; + } + + LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + + if(m_bChildMaximized && (BOOL)wParam) + { + LPNCCALCSIZE_PARAMS lpParams = (LPNCCALCSIZE_PARAMS)lParam; + if(m_bLayoutRTL) + { + lpParams->rgrc[0].left += m_cxRight; + lpParams->rgrc[0].right -= m_cxLeft; + } + else + { + lpParams->rgrc[0].left += m_cxLeft; + lpParams->rgrc[0].right -= m_cxRight; + } + } + + return lRet; + } + + LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + + if(!m_bChildMaximized) + return lRet; + + ATLASSERT(m_hWndChildMaximized != NULL && m_hIconChildMaximized != NULL); + + // get DC and window rectangle + CWindowDC dc(m_hWnd); + RECT rect; + GetWindowRect(&rect); + int cxWidth = rect.right - rect.left; + int cyHeight = rect.bottom - rect.top; + + // paint left side nonclient background and draw icon + ::SetRect(&rect, 0, 0, m_cxLeft, cyHeight); +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { + if(m_pfnDrawThemeParentBackground != NULL) + m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect); + else + dc.FillRect(&rect, COLOR_WINDOW); + } + else +#endif // !_WTL_NO_AUTO_THEME + { + if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0) + dc.FillRect(&rect, COLOR_3DFACE); + else + dc.FillRect(&rect, COLOR_MENU); + } + + RECT rcIcon = { 0 }; + T* pT = static_cast(this); + pT->_CalcIconRect(cxWidth, cyHeight, rcIcon); + dc.DrawIconEx(rcIcon.left, rcIcon.top, m_hIconChildMaximized, m_cxIconWidth, m_cyIconHeight); + + // paint right side nonclient background + ::SetRect(&rect, cxWidth - m_cxRight, 0, cxWidth, cyHeight); +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { + if(m_pfnDrawThemeParentBackground != NULL) + { + // this is to account for the left non-client area + POINT ptOrg = { 0, 0 }; + dc.GetViewportOrg(&ptOrg); + dc.SetViewportOrg(ptOrg.x + m_cxLeft, ptOrg.y); + ::OffsetRect(&rect, -m_cxLeft, 0); + + m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect); + + // restore + dc.SetViewportOrg(ptOrg); + ::OffsetRect(&rect, m_cxLeft, 0); + } + else + { + dc.FillRect(&rect, COLOR_3DFACE); + } + } + else +#endif // !_WTL_NO_AUTO_THEME + { + if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0) + dc.FillRect(&rect, COLOR_3DFACE); + else + dc.FillRect(&rect, COLOR_MENU); + } + + // draw buttons + RECT arrRect[3] = { 0 }; + pT->_CalcBtnRects(cxWidth, cyHeight, arrRect); + pT->_DrawMDIButton(dc, arrRect, -1); // draw all buttons + + return lRet; + } + + LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + if(m_bChildMaximized) + { + RECT rect = { 0 }; + GetWindowRect(&rect); + POINT pt = { GET_X_LPARAM(lParam) - rect.left, GET_Y_LPARAM(lParam) - rect.top }; + if(m_bLayoutRTL) + { + if((pt.x < m_cxRight) || (pt.x > ((rect.right - rect.left) - m_cxLeft))) + lRet = HTBORDER; + } + else + { + if((pt.x < m_cxLeft) || (pt.x > ((rect.right - rect.left) - m_cxRight))) + lRet = HTBORDER; + } + } + return lRet; + } + + LRESULT OnNcLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(!m_bChildMaximized) + { + bHandled = FALSE; + return 1; + } + + ATLASSERT(_DebugCheckChild()); + + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + RECT rect = { 0 }; + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + RECT rcIcon = { 0 }; + T* pT = static_cast(this); + pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL); + RECT arrRect[3] = { 0 }; + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); + + if(::PtInRect(&rcIcon, pt)) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: icon\n")); +#endif +#ifndef TPM_VERPOSANIMATION + const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag +#endif + CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE); + UINT uRet = (UINT)menu.TrackPopupMenu(TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | + (s_bW2K ? TPM_VERPOSANIMATION : 0), m_bLayoutRTL ? rect.right : rect.left, rect.bottom, m_hWndChildMaximized); + + // eat next message if click is on the same button + ::OffsetRect(&rcIcon, rect.left, rect.top); + MSG msg = { 0 }; + if(::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rcIcon, msg.pt)) + ::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_REMOVE); + + if(uRet != 0) + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uRet, 0L); + } + else if(::PtInRect(&arrRect[0], pt)) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: close button\n")); +#endif + m_nBtnWasPressed = m_nBtnPressed = 0; + } + else if(::PtInRect(&arrRect[1], pt)) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: restore button\n")); +#endif + m_nBtnWasPressed = m_nBtnPressed = 1; + } + else if(::PtInRect(&arrRect[2], pt)) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: minimize button\n")); +#endif + m_nBtnWasPressed = m_nBtnPressed = 2; + } + else + { + bHandled = FALSE; + } + + // draw the button state if it was pressed + if(m_nBtnPressed != -1) + { + SetCapture(); + CWindowDC dc(m_hWnd); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect); + pT->_DrawMDIButton(dc, arrRect, m_nBtnPressed); + } + + return 0; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1) + { + bHandled = FALSE; + return 1; + } + + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ClientToScreen(&pt); + RECT rect = { 0 }; + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + RECT arrRect[3] = { 0 }; + T* pT = static_cast(this); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); + int nOldBtnPressed = m_nBtnPressed; + m_nBtnPressed = ::PtInRect(&arrRect[m_nBtnWasPressed], pt) ? m_nBtnWasPressed : -1; + if(nOldBtnPressed != m_nBtnPressed) + { + CWindowDC dc(m_hWnd); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect); + pT->_DrawMDIButton(dc, arrRect, (m_nBtnPressed != -1) ? m_nBtnPressed : nOldBtnPressed); + } + + return 0; + } + + LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1) + { + bHandled = FALSE; + return 1; + } + + ATLASSERT(_DebugCheckChild()); + + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ClientToScreen(&pt); + RECT rect = { 0 }; + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + int nBtn = m_nBtnWasPressed; + ReleaseCapture(); + + RECT arrRect[3] = { 0 }; + T* pT = static_cast(this); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); + if(::PtInRect(&arrRect[nBtn], pt)) + { + switch(nBtn) + { + case 0: // close +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: close button\n")); +#endif + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_CLOSE, 0L); + break; + case 1: // restore +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: restore button\n")); +#endif + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_RESTORE, 0L); + break; + case 2: // minimize +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: minimize button\n")); +#endif + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_MINIMIZE, 0L); + break; + default: + break; + } + } + + return 0; + } + + LRESULT OnNcLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(!m_bChildMaximized || m_nBtnWasPressed != -1) + { + bHandled = FALSE; + return 1; + } + + ATLASSERT(_DebugCheckChild()); + + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + RECT rect = { 0 }; + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + + RECT rcIcon = { 0 }; + T* pT = static_cast(this); + pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL); + RECT arrRect[3] = { 0 }; + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); + + if(::PtInRect(&rcIcon, pt)) + { + CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE); + UINT uDefID = menu.GetMenuDefaultItem(); + if(uDefID == (UINT)-1) + uDefID = SC_CLOSE; + ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uDefID, 0L); + } + + return 0; + } + + LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bChildMaximized) + { + if(m_nBtnPressed != -1) + { + ATLASSERT(m_nBtnPressed == m_nBtnWasPressed); // must be + m_nBtnPressed = -1; + RECT rect = { 0 }; + GetWindowRect(&rect); + RECT arrRect[3] = { 0 }; + T* pT = static_cast(this); + pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect); + CWindowDC dc(m_hWnd); + pT->_DrawMDIButton(dc, arrRect, m_nBtnWasPressed); + } + m_nBtnWasPressed = -1; + } + else + { + bHandled = FALSE; + } + return 0; + } + +// Parent window message handlers + LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + m_bParentActive = (LOWORD(wParam) != WA_INACTIVE); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW); + bHandled = FALSE; + return 1; + } + +// MDI client window message handlers + LRESULT OnMDISetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + m_wndMDIClient.DefWindowProc(uMsg, NULL, lParam); + HMENU hOldMenu = GetMenu(); + BOOL bRet = AttachMenu((HMENU)wParam); + bRet; // avoid level 4 warning + ATLASSERT(bRet); + +#if (_WIN32_IE >= 0x0400) + T* pT = static_cast(this); + pT->UpdateRebarBandIdealSize(); +#endif // (_WIN32_IE >= 0x0400) + + return (LRESULT)hOldMenu; + } + +// All messages from the message hook + LRESULT OnAllHookMessages(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->_ProcessAllHookMessages(uMsg, wParam, lParam); + + bHandled = FALSE; + return 1; + } + +// Overrideables + // override this to provide different ideal size + void UpdateRebarBandIdealSize() + { + // assuming we are in a rebar, change ideal size to our size + // we hope that if we are not in a rebar, nCount will be 0 + int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L); + for(int i = 0; i < nCount; i++) + { + REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE }; + ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); + if(rbi.hwndChild == m_hWnd) + { + rbi.fMask = RBBIM_IDEALSIZE; + rbi.cxIdeal = m_bChildMaximized ? m_cxLeft + m_cxRight : 0; + int nBtnCount = GetButtonCount(); + if(nBtnCount > 0) + { + RECT rect = { 0 }; + GetItemRect(nBtnCount - 1, &rect); + rbi.cxIdeal += rect.right; + } + ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); + break; + } + } + } + + // all hook messages - check for the maximized MDI child window change + void _ProcessAllHookMessages(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/) + { + if(uMsg == WM_MDIGETACTIVE || uMsg == WM_MDISETMENU) + return; + + BOOL bMaximized = FALSE; + HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); + bool bMaxOld = m_bChildMaximized; + m_bChildMaximized = (hWndChild != NULL && bMaximized); + HICON hIconOld = m_hIconChildMaximized; + + if(m_bChildMaximized) + { + if(m_hWndChildMaximized != hWndChild) + { + ATL::CWindow wnd = m_hWndChildMaximized = hWndChild; + m_hIconChildMaximized = wnd.GetIcon(FALSE); + if(m_hIconChildMaximized == NULL) + { + m_hIconChildMaximized = wnd.GetIcon(TRUE); + if(m_hIconChildMaximized == NULL) + { + // no icon set with WM_SETICON, get the class one +// need conditional code because types don't match in winuser.h +#ifdef _WIN64 + m_hIconChildMaximized = (HICON)::GetClassLongPtr(wnd, GCLP_HICONSM); +#else + m_hIconChildMaximized = (HICON)LongToHandle(::GetClassLongPtr(wnd, GCLP_HICONSM)); +#endif + } + } + } + } + else + { + m_hWndChildMaximized = NULL; + m_hIconChildMaximized = NULL; + } + + if(bMaxOld != m_bChildMaximized) + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - All messages hook change: m_bChildMaximized = %s\n"), m_bChildMaximized ? "true" : "false"); +#endif + // assuming we are in a rebar, change our size to accomodate new state + // we hope that if we are not in a rebar, nCount will be 0 + int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L); + int cxDiff = (m_bChildMaximized ? 1 : -1) * (m_cxLeft + m_cxRight); + for(int i = 0; i < nCount; i++) + { +#if (_WIN32_IE >= 0x0500) + REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE }; + ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); + if(rbi.hwndChild == m_hWnd) + { + if((rbi.fStyle & RBBS_USECHEVRON) != 0) + { + rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE; + rbi.cxMinChild += cxDiff; + rbi.cxIdeal += cxDiff; + ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); + } + break; + } +#elif (_WIN32_IE >= 0x0400) + REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE }; + ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); + if(rbi.hwndChild == m_hWnd) + { + rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE; + rbi.cxMinChild += cxDiff; + rbi.cxIdeal += cxDiff; + ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); + break; + } +#else // (_WIN32_IE < 0x0400) + REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE }; + ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); + if(rbi.hwndChild == m_hWnd) + { + rbi.fMask = RBBIM_CHILDSIZE; + rbi.cxMinChild += cxDiff; + ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); + break; + } +#endif // (_WIN32_IE < 0x0400) + } + } + + if(bMaxOld != m_bChildMaximized || hIconOld != m_hIconChildMaximized) + { + // force size change and redraw everything + RECT rect = { 0 }; + GetWindowRect(&rect); + ::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rect, 2); + SetRedraw(FALSE); + SetWindowPos(NULL, 0, 0, 1, 1, SWP_NOZORDER | SWP_NOMOVE); + SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE); + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW); + } + } + +// Implementation + void GetSystemSettings() + { +#ifdef _CMDBAR_EXTRA_TRACE + ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - GetSystemSettings\n")); +#endif + _baseClass::GetSystemSettings(); + + NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0); + ATLASSERT(bRet); + if(bRet) + { + m_cxIconWidth = ::GetSystemMetrics(SM_CXSMICON); + m_cyIconHeight = ::GetSystemMetrics(SM_CYSMICON); + m_cxLeft = m_cxIconWidth; + +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { + m_cxBtnWidth = info.iCaptionWidth - 2 * m_cxyOffset; + m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset; + m_cxRight = 3 * m_cxBtnWidth; + } + else +#endif // !_WTL_NO_AUTO_THEME + { + m_cxBtnWidth = info.iCaptionWidth - m_cxyOffset; + m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset; + m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset; + } + } + + RECT rect = { 0 }; + GetClientRect(&rect); + T* pT = static_cast(this); + pT->_AdjustBtnSize(rect.bottom); + } + + void _AdjustBtnSize(int cyHeight) + { + if(cyHeight > 1 && m_cyBtnHeight > cyHeight) + { +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { + m_cyBtnHeight = cyHeight; + m_cxBtnWidth = cyHeight; + m_cxRight = 3 * m_cxBtnWidth; + } + else +#endif // !_WTL_NO_AUTO_THEME + { + m_cyBtnHeight = cyHeight; + m_cxBtnWidth = cyHeight + m_cxyOffset; + m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset; + } + } + } + + void _CalcIconRect(int cxWidth, int cyHeight, RECT& rect, bool bInvertX = false) const + { + int xStart = (m_cxLeft - m_cxIconWidth) / 2; + if(xStart < 0) + xStart = 0; + int yStart = (cyHeight - m_cyIconHeight) / 2; + if(yStart < 0) + yStart = 0; + + if(bInvertX) + ::SetRect(&rect, cxWidth - (xStart + m_cxBtnWidth), yStart, cxWidth - xStart, yStart + m_cyBtnHeight); + else + ::SetRect(&rect, xStart, yStart, xStart + m_cxBtnWidth, yStart + m_cyBtnHeight); + } + + void _CalcBtnRects(int cxWidth, int cyHeight, RECT arrRect[3], bool bInvertX = false) const + { + int yStart = (cyHeight - m_cyBtnHeight) / 2; + if(yStart < 0) + yStart = 0; + + RECT rcBtn = { cxWidth - m_cxBtnWidth, yStart, cxWidth, yStart + m_cyBtnHeight }; + int nDirection = -1; + if(bInvertX) + { + ::SetRect(&rcBtn, 0, yStart, m_cxBtnWidth, yStart + m_cyBtnHeight); + nDirection = 1; + } + + arrRect[0] = rcBtn; +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0); + else +#endif // !_WTL_NO_AUTO_THEME + ::OffsetRect(&rcBtn, nDirection * (m_cxBtnWidth + m_cxyOffset), 0); + arrRect[1] = rcBtn; + ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0); + arrRect[2] = rcBtn; + } + + void _DrawMDIButton(CWindowDC& dc, LPRECT pRects, int nBtn) + { +#ifndef _WTL_NO_AUTO_THEME + if(m_hTheme != NULL) + { +#ifndef TMSCHEMA_H + const int WP_MDICLOSEBUTTON = 20; + const int CBS_NORMAL = 1; + const int CBS_PUSHED = 3; + const int CBS_DISABLED = 4; + const int WP_MDIRESTOREBUTTON = 22; + const int RBS_NORMAL = 1; + const int RBS_PUSHED = 3; + const int RBS_DISABLED = 4; + const int WP_MDIMINBUTTON = 16; + const int MINBS_NORMAL = 1; + const int MINBS_PUSHED = 3; + const int MINBS_DISABLED = 4; +#endif // TMSCHEMA_H + if(nBtn == -1 || nBtn == 0) + m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDICLOSEBUTTON, m_bParentActive ? ((m_nBtnPressed == 0) ? CBS_PUSHED : CBS_NORMAL) : CBS_DISABLED, &pRects[0], NULL); + if(nBtn == -1 || nBtn == 1) + m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIRESTOREBUTTON, m_bParentActive ? ((m_nBtnPressed == 1) ? RBS_PUSHED : RBS_NORMAL) : RBS_DISABLED, &pRects[1], NULL); + if(nBtn == -1 || nBtn == 2) + m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIMINBUTTON, m_bParentActive ? ((m_nBtnPressed == 2) ? MINBS_PUSHED : MINBS_NORMAL) : MINBS_DISABLED, &pRects[2], NULL); + } + else +#endif // !_WTL_NO_AUTO_THEME + { + if(nBtn == -1 || nBtn == 0) + dc.DrawFrameControl(&pRects[0], DFC_CAPTION, DFCS_CAPTIONCLOSE | ((m_nBtnPressed == 0) ? DFCS_PUSHED : 0)); + if(nBtn == -1 || nBtn == 1) + dc.DrawFrameControl(&pRects[1], DFC_CAPTION, DFCS_CAPTIONRESTORE | ((m_nBtnPressed == 1) ? DFCS_PUSHED : 0)); + if(nBtn == -1 || nBtn == 2) + dc.DrawFrameControl(&pRects[2], DFC_CAPTION, DFCS_CAPTIONMIN | ((m_nBtnPressed == 2) ? DFCS_PUSHED : 0)); + } + } + +#ifndef _WTL_NO_AUTO_THEME + static UINT _GetThemeChangedMsg() + { +#ifndef WM_THEMECHANGED + static const UINT WM_THEMECHANGED = 0x031A; +#endif // !WM_THEMECHANGED + return WM_THEMECHANGED; + } + + void _OpenThemeData() + { + ATLASSERT(m_hThemeDLL != NULL); + + PFN_OpenThemeData pfnOpenThemeData = (PFN_OpenThemeData)::GetProcAddress(m_hThemeDLL, "OpenThemeData"); + ATLASSERT(pfnOpenThemeData != NULL); + if(pfnOpenThemeData != NULL) + m_hTheme = pfnOpenThemeData(m_hWnd, L"Window"); + } + + void _CloseThemeData() + { + ATLASSERT(m_hThemeDLL != NULL); + + if(m_hTheme == NULL) + return; // nothing to do + + PFN_CloseThemeData pfnCloseThemeData = (PFN_CloseThemeData)::GetProcAddress(m_hThemeDLL, "CloseThemeData"); + ATLASSERT(pfnCloseThemeData != NULL); + if(pfnCloseThemeData != NULL) + { + pfnCloseThemeData(m_hTheme); + m_hTheme = NULL; + } + } +#endif // !_WTL_NO_AUTO_THEME + + bool _DebugCheckChild() + { +#ifdef _DEBUG + BOOL bMaximized = FALSE; + HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); + return (bMaximized && hWndChild == m_hWndChildMaximized); +#else // !_DEBUG + return true; +#endif // !_DEBUG + } +}; + +class CMDICommandBarCtrl : public CMDICommandBarCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_MDICommandBar"), GetWndClassName()) +}; + +}; // namespace WTL + +#endif // __ATLCTRLW_H__ diff --git a/wtl/wtl/include/atlctrlx.h b/wtl/wtl/include/atlctrlx.h new file mode 100644 index 00000000..bd78e3f9 --- /dev/null +++ b/wtl/wtl/include/atlctrlx.h @@ -0,0 +1,4827 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLCTRLX_H__ +#define __ATLCTRLX_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlctrlx.h requires atlapp.h to be included first +#endif + +#ifndef __ATLCTRLS_H__ + #error atlctrlx.h requires atlctrls.h to be included first +#endif + +#ifndef WM_UPDATEUISTATE + #define WM_UPDATEUISTATE 0x0128 +#endif // !WM_UPDATEUISTATE + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CBitmapButtonImpl +// CBitmapButton +// CCheckListViewCtrlImpl +// CCheckListViewCtrl +// CHyperLinkImpl +// CHyperLink +// CWaitCursor +// CCustomWaitCursor +// CMultiPaneStatusBarCtrlImpl +// CMultiPaneStatusBarCtrl +// CPaneContainerImpl +// CPaneContainer +// CSortListViewImpl +// CSortListViewCtrlImpl +// CSortListViewCtrl +// CTabViewImpl +// CTabView + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CBitmapButton - bitmap button implementation + +#ifndef _WIN32_WCE + +// bitmap button extended styles +#define BMPBTN_HOVER 0x00000001 +#define BMPBTN_AUTO3D_SINGLE 0x00000002 +#define BMPBTN_AUTO3D_DOUBLE 0x00000004 +#define BMPBTN_AUTOSIZE 0x00000008 +#define BMPBTN_SHAREIMAGELISTS 0x00000010 +#define BMPBTN_AUTOFIRE 0x00000020 + +template +class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits> +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + + enum + { + _nImageNormal = 0, + _nImagePushed, + _nImageFocusOrHover, + _nImageDisabled, + + _nImageCount = 4, + }; + + enum + { + ID_TIMER_FIRST = 1000, + ID_TIMER_REPEAT = 1001 + }; + + // Bitmap button specific extended styles + DWORD m_dwExtendedStyle; + + CImageList m_ImageList; + int m_nImage[_nImageCount]; + + CToolTipCtrl m_tip; + LPTSTR m_lpstrToolTipText; + + // Internal states + unsigned m_fMouseOver:1; + unsigned m_fFocus:1; + unsigned m_fPressed:1; + + +// Constructor/Destructor + CBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : + m_ImageList(hImageList), m_dwExtendedStyle(dwExtendedStyle), + m_lpstrToolTipText(NULL), + m_fMouseOver(0), m_fFocus(0), m_fPressed(0) + { + m_nImage[_nImageNormal] = -1; + m_nImage[_nImagePushed] = -1; + m_nImage[_nImageFocusOrHover] = -1; + m_nImage[_nImageDisabled] = -1; + } + + ~CBitmapButtonImpl() + { + if((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0) + m_ImageList.Destroy(); + delete [] m_lpstrToolTipText; + } + + // overridden to provide proper initialization + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet) + Init(); + return bRet; + } + +// Attributes + DWORD GetBitmapButtonExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + return dwPrevStyle; + } + + HIMAGELIST GetImageList() const + { + return m_ImageList; + } + + HIMAGELIST SetImageList(HIMAGELIST hImageList) + { + HIMAGELIST hImageListPrev = m_ImageList; + m_ImageList = hImageList; + if((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0 && ::IsWindow(m_hWnd)) + SizeToImage(); + return hImageListPrev; + } + + int GetToolTipTextLength() const + { + return (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTipText); + } + + bool GetToolTipText(LPTSTR lpstrText, int nLength) const + { + ATLASSERT(lpstrText != NULL); + if(m_lpstrToolTipText == NULL) + return false; + + errno_t nRet = SecureHelper::strncpy_x(lpstrText, nLength, m_lpstrToolTipText, _TRUNCATE); + + return (nRet == 0 || nRet == STRUNCATE); + } + + bool SetToolTipText(LPCTSTR lpstrText) + { + if(m_lpstrToolTipText != NULL) + { + delete [] m_lpstrToolTipText; + m_lpstrToolTipText = NULL; + } + + if(lpstrText == NULL) + { + if(m_tip.IsWindow()) + m_tip.Activate(FALSE); + return true; + } + + int cchLen = lstrlen(lpstrText) + 1; + ATLTRY(m_lpstrToolTipText = new TCHAR[cchLen]); + if(m_lpstrToolTipText == NULL) + return false; + + SecureHelper::strcpy_x(m_lpstrToolTipText, cchLen, lpstrText); + if(m_tip.IsWindow()) + { + m_tip.Activate(TRUE); + m_tip.AddTool(m_hWnd, m_lpstrToolTipText); + } + + return true; + } + +// Operations + void SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, int nDisabled = -1) + { + if(nNormal != -1) + m_nImage[_nImageNormal] = nNormal; + if(nPushed != -1) + m_nImage[_nImagePushed] = nPushed; + if(nFocusOrHover != -1) + m_nImage[_nImageFocusOrHover] = nFocusOrHover; + if(nDisabled != -1) + m_nImage[_nImageDisabled] = nDisabled; + } + + BOOL SizeToImage() + { + ATLASSERT(::IsWindow(m_hWnd) && m_ImageList.m_hImageList != NULL); + int cx = 0; + int cy = 0; + if(!m_ImageList.GetIconSize(cx, cy)) + return FALSE; + return ResizeClient(cx, cy); + } + +// Overrideables + void DoPaint(CDCHandle dc) + { + ATLASSERT(m_ImageList.m_hImageList != NULL); // image list must be set + ATLASSERT(m_nImage[0] != -1); // main bitmap must be set + + // set bitmap according to the current button state + int nImage = -1; + bool bHover = IsHoverMode(); + if(!IsWindowEnabled()) + nImage = m_nImage[_nImageDisabled]; + else if(m_fPressed == 1) + nImage = m_nImage[_nImagePushed]; + else if((!bHover && m_fFocus == 1) || (bHover && m_fMouseOver == 1)) + nImage = m_nImage[_nImageFocusOrHover]; + if(nImage == -1) // not there, use default one + nImage = m_nImage[_nImageNormal]; + + // draw the button image + int xyPos = 0; + if((m_fPressed == 1) && ((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0) && (m_nImage[_nImagePushed] == -1)) + xyPos = 1; + m_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL); + + // draw 3D border if required + if((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0) + { + RECT rect; + GetClientRect(&rect); + + if(m_fPressed == 1) + dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT); + else if(!bHover || m_fMouseOver == 1) + dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT); + + if(!bHover && m_fFocus == 1) + { + ::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE)); + dc.DrawFocusRect(&rect); + } + } + } + +// Message map and handlers + BEGIN_MSG_MAP(CBitmapButtonImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + MESSAGE_HANDLER(WM_SETFOCUS, OnFocus) + MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) + MESSAGE_HANDLER(WM_ENABLE, OnEnable) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) + MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) + MESSAGE_HANDLER(WM_KEYUP, OnKeyUp) + MESSAGE_HANDLER(WM_TIMER, OnTimer) + MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + Init(); + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_tip.IsWindow()) + { + m_tip.DestroyWindow(); + m_tip.m_hWnd = NULL; + } + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + MSG msg = { m_hWnd, uMsg, wParam, lParam }; + if(m_tip.IsWindow()) + m_tip.RelayEvent(&msg); + bHandled = FALSE; + return 1; + } + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + if(wParam != NULL) + { + pT->DoPaint((HDC)wParam); + } + else + { + CPaintDC dc(m_hWnd); + pT->DoPaint(dc.m_hDC); + } + return 0; + } + + LRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + m_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0; + Invalidate(); + UpdateWindow(); + bHandled = FALSE; + return 1; + } + + LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = 0; + if(IsHoverMode()) + SetCapture(); + else + lRet = DefWindowProc(uMsg, wParam, lParam); + if(::GetCapture() == m_hWnd) + { + m_fPressed = 1; + Invalidate(); + UpdateWindow(); + } + if((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) + { + int nElapse = 250; + int nDelay = 0; + if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0)) + nElapse += nDelay * 250; // all milli-seconds + SetTimer(ID_TIMER_FIRST, nElapse); + } + return lRet; + } + + LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = 0; + if(!IsHoverMode()) + lRet = DefWindowProc(uMsg, wParam, lParam); + if(::GetCapture() != m_hWnd) + SetCapture(); + if(m_fPressed == 0) + { + m_fPressed = 1; + Invalidate(); + UpdateWindow(); + } + return lRet; + } + + LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = 0; + bool bHover = IsHoverMode(); + if(!bHover) + lRet = DefWindowProc(uMsg, wParam, lParam); + if(::GetCapture() == m_hWnd) + { + if(bHover && m_fPressed == 1) + ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); + ::ReleaseCapture(); + } + return lRet; + } + + LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_fPressed == 1) + { + m_fPressed = 0; + Invalidate(); + UpdateWindow(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + Invalidate(); + UpdateWindow(); + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(::GetCapture() == m_hWnd) + { + POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ClientToScreen(&ptCursor); + RECT rect = { 0 }; + GetWindowRect(&rect); + unsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0; + if(m_fPressed != uPressed) + { + m_fPressed = uPressed; + Invalidate(); + UpdateWindow(); + } + } + else if(IsHoverMode() && m_fMouseOver == 0) + { + m_fMouseOver = 1; + Invalidate(); + UpdateWindow(); + StartTrackMouseLeave(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_fMouseOver == 1) + { + m_fMouseOver = 0; + Invalidate(); + UpdateWindow(); + } + return 0; + } + + LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam == VK_SPACE && IsHoverMode()) + return 0; // ignore if in hover mode + if(wParam == VK_SPACE && m_fPressed == 0) + { + m_fPressed = 1; + Invalidate(); + UpdateWindow(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam == VK_SPACE && IsHoverMode()) + return 0; // ignore if in hover mode + if(wParam == VK_SPACE && m_fPressed == 1) + { + m_fPressed = 0; + Invalidate(); + UpdateWindow(); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + ATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0); + switch(wParam) // timer ID + { + case ID_TIMER_FIRST: + KillTimer(ID_TIMER_FIRST); + if(m_fPressed == 1) + { + ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); + int nElapse = 250; + int nRepeat = 40; + if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0)) + nElapse = 10000 / (10 * nRepeat + 25); // milli-seconds, approximated + SetTimer(ID_TIMER_REPEAT, nElapse); + } + break; + case ID_TIMER_REPEAT: + if(m_fPressed == 1) + ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); + else if(::GetCapture() != m_hWnd) + KillTimer(ID_TIMER_REPEAT); + break; + default: // not our timer + break; + } + return 0; + } + + LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + // If the control is subclassed or superclassed, this message can cause + // repainting without WM_PAINT. We don't use this state, so just do nothing. + return 0; + } + +// Implementation + void Init() + { + // We need this style to prevent Windows from painting the button + ModifyStyle(0, BS_OWNERDRAW); + + // create a tool tip + m_tip.Create(m_hWnd); + ATLASSERT(m_tip.IsWindow()); + if(m_tip.IsWindow() && m_lpstrToolTipText != NULL) + { + m_tip.Activate(TRUE); + m_tip.AddTool(m_hWnd, m_lpstrToolTipText); + } + + if(m_ImageList.m_hImageList != NULL && (m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0) + SizeToImage(); + } + + BOOL StartTrackMouseLeave() + { + TRACKMOUSEEVENT tme = { 0 }; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = m_hWnd; + return _TrackMouseEvent(&tme); + } + + bool IsHoverMode() const + { + return ((m_dwExtendedStyle & BMPBTN_HOVER) != 0); + } +}; + + +class CBitmapButton : public CBitmapButtonImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName()) + + CBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : + CBitmapButtonImpl(dwExtendedStyle, hImageList) + { } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CCheckListCtrlView - list view control with check boxes + +template +class CCheckListViewCtrlImplTraits +{ +public: + static DWORD GetWndStyle(DWORD dwStyle) + { + return (dwStyle == 0) ? t_dwStyle : dwStyle; + } + + static DWORD GetWndExStyle(DWORD dwExStyle) + { + return (dwExStyle == 0) ? t_dwExStyle : dwExStyle; + } + + static DWORD GetExtendedLVStyle() + { + return t_dwExListViewStyle; + } +}; + +typedef CCheckListViewCtrlImplTraits CCheckListViewCtrlTraits; + +template +class ATL_NO_VTABLE CCheckListViewCtrlImpl : public ATL::CWindowImpl +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + +// Attributes + static DWORD GetExtendedLVStyle() + { + return TWinTraits::GetExtendedLVStyle(); + } + +// Operations + BOOL SubclassWindow(HWND hWnd) + { +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImplBaseT< TBase, TWinTraits>::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImplBaseT< TBase, TWinTraits> _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet) + { + T* pT = static_cast(this); + pT; + ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0); + SetExtendedListViewStyle(pT->GetExtendedLVStyle()); + } + return bRet; + } + + void CheckSelectedItems(int nCurrItem) + { + // first check if this item is selected + LVITEM lvi = { 0 }; + lvi.iItem = nCurrItem; + lvi.iSubItem = 0; + lvi.mask = LVIF_STATE; + lvi.stateMask = LVIS_SELECTED; + GetItem(&lvi); + // if item is not selected, don't do anything + if(!(lvi.state & LVIS_SELECTED)) + return; + // new check state will be reverse of the current state, + BOOL bCheck = !GetCheckState(nCurrItem); + int nItem = -1; + int nOldItem = -1; + while((nItem = GetNextItem(nOldItem, LVNI_SELECTED)) != -1) + { + if(nItem != nCurrItem) + SetCheckState(nItem, bCheck); + nOldItem = nItem; + } + } + +// Implementation + BEGIN_MSG_MAP(CCheckListViewCtrlImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown) + MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) + END_MSG_MAP() + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + // first let list view control initialize everything + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + T* pT = static_cast(this); + pT; + ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0); + SetExtendedListViewStyle(pT->GetExtendedLVStyle()); + return lRet; + } + + LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + POINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + LVHITTESTINFO lvh = { 0 }; + lvh.pt = ptMsg; + if(HitTest(&lvh) != -1 && lvh.flags == LVHT_ONITEMSTATEICON && ::GetKeyState(VK_CONTROL) >= 0) + { + T* pT = static_cast(this); + pT->CheckSelectedItems(lvh.iItem); + } + bHandled = FALSE; + return 1; + } + + LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam == VK_SPACE) + { + int nCurrItem = GetNextItem(-1, LVNI_FOCUSED); + if(nCurrItem != -1 && ::GetKeyState(VK_CONTROL) >= 0) + { + T* pT = static_cast(this); + pT->CheckSelectedItems(nCurrItem); + } + } + bHandled = FALSE; + return 1; + } +}; + +class CCheckListViewCtrl : public CCheckListViewCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName()) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CHyperLink - hyper link control implementation + +#if (WINVER < 0x0500) && !defined(_WIN32_WCE) +__declspec(selectany) struct +{ + enum { cxWidth = 32, cyHeight = 32 }; + int xHotSpot; + int yHotSpot; + unsigned char arrANDPlane[cxWidth * cyHeight / 8]; + unsigned char arrXORPlane[cxWidth * cyHeight / 8]; +} _AtlHyperLink_CursorData = +{ + 5, 0, + { + 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, + 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, + 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, + 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, + 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }, + { + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00, + 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00, + 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00, + 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, + 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + } +}; +#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE) + +#define HLINK_UNDERLINED 0x00000000 +#define HLINK_NOTUNDERLINED 0x00000001 +#define HLINK_UNDERLINEHOVER 0x00000002 +#define HLINK_COMMANDBUTTON 0x00000004 +#define HLINK_NOTIFYBUTTON 0x0000000C +#define HLINK_USETAGS 0x00000010 +#define HLINK_USETAGSBOLD 0x00000030 +#define HLINK_NOTOOLTIP 0x00000040 + +// Notes: +// - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned +// - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored + +template +class ATL_NO_VTABLE CHyperLinkImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > +{ +public: + LPTSTR m_lpstrLabel; + LPTSTR m_lpstrHyperLink; + + HCURSOR m_hCursor; + HFONT m_hFont; + HFONT m_hFontNormal; + + RECT m_rcLink; +#ifndef _WIN32_WCE + CToolTipCtrl m_tip; +#endif // !_WIN32_WCE + + COLORREF m_clrLink; + COLORREF m_clrVisited; + + DWORD m_dwExtendedStyle; // Hyper Link specific extended styles + + bool m_bPaintLabel:1; + bool m_bVisited:1; + bool m_bHover:1; + bool m_bInternalLinkFont:1; + + +// Constructor/Destructor + CHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) : + m_lpstrLabel(NULL), m_lpstrHyperLink(NULL), + m_hCursor(NULL), m_hFont(NULL), m_hFontNormal(NULL), + m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)), + m_dwExtendedStyle(dwExtendedStyle), + m_bPaintLabel(true), m_bVisited(false), + m_bHover(false), m_bInternalLinkFont(false) + { + ::SetRectEmpty(&m_rcLink); + } + + ~CHyperLinkImpl() + { + delete [] m_lpstrLabel; + delete [] m_lpstrHyperLink; + if(m_bInternalLinkFont && m_hFont != NULL) + ::DeleteObject(m_hFont); +#if (WINVER < 0x0500) && !defined(_WIN32_WCE) + // It was created, not loaded, so we have to destroy it + if(m_hCursor != NULL) + ::DestroyCursor(m_hCursor); +#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE) + } + +// Attributes + DWORD GetHyperLinkExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetHyperLinkExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + return dwPrevStyle; + } + + bool GetLabel(LPTSTR lpstrBuffer, int nLength) const + { + if(m_lpstrLabel == NULL) + return false; + ATLASSERT(lpstrBuffer != NULL); + if(nLength <= lstrlen(m_lpstrLabel)) + return false; + + SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrLabel); + + return true; + } + + bool SetLabel(LPCTSTR lpstrLabel) + { + delete [] m_lpstrLabel; + m_lpstrLabel = NULL; + int cchLen = lstrlen(lpstrLabel) + 1; + ATLTRY(m_lpstrLabel = new TCHAR[cchLen]); + if(m_lpstrLabel == NULL) + return false; + + SecureHelper::strcpy_x(m_lpstrLabel, cchLen, lpstrLabel); + T* pT = static_cast(this); + pT->CalcLabelRect(); + + if(m_hWnd != NULL) + SetWindowText(lpstrLabel); // Set this for accessibility + + return true; + } + + bool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const + { + if(m_lpstrHyperLink == NULL) + return false; + ATLASSERT(lpstrBuffer != NULL); + if(nLength <= lstrlen(m_lpstrHyperLink)) + return false; + + SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrHyperLink); + + return true; + } + + bool SetHyperLink(LPCTSTR lpstrLink) + { + delete [] m_lpstrHyperLink; + m_lpstrHyperLink = NULL; + int cchLen = lstrlen(lpstrLink) + 1; + ATLTRY(m_lpstrHyperLink = new TCHAR[cchLen]); + if(m_lpstrHyperLink == NULL) + return false; + + SecureHelper::strcpy_x(m_lpstrHyperLink, cchLen, lpstrLink); + if(m_lpstrLabel == NULL) + { + T* pT = static_cast(this); + pT->CalcLabelRect(); + } +#ifndef _WIN32_WCE + if(m_tip.IsWindow()) + { + m_tip.Activate(TRUE); + m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1); + } +#endif // !_WIN32_WCE + return true; + } + + HFONT GetLinkFont() const + { + return m_hFont; + } + + void SetLinkFont(HFONT hFont) + { + if(m_bInternalLinkFont && m_hFont != NULL) + { + ::DeleteObject(m_hFont); + m_bInternalLinkFont = false; + } + m_hFont = hFont; + } + + int GetIdealHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) + return -1; + if(!m_bPaintLabel) + return -1; + + CClientDC dc(m_hWnd); + RECT rect = { 0 }; + GetClientRect(&rect); + HFONT hFontOld = dc.SelectFont(m_hFontNormal); + RECT rcText = rect; + dc.DrawText(_T("NS"), -1, &rcText, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); + dc.SelectFont(m_hFont); + RECT rcLink = rect; + dc.DrawText(_T("NS"), -1, &rcLink, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); + dc.SelectFont(hFontOld); + return max(rcText.bottom - rcText.top, rcLink.bottom - rcLink.top); + } + + bool GetIdealSize(SIZE& size) const + { + int cx = 0, cy = 0; + bool bRet = GetIdealSize(cx, cy); + if(bRet) + { + size.cx = cx; + size.cy = cy; + } + return bRet; + } + + bool GetIdealSize(int& cx, int& cy) const + { + ATLASSERT(::IsWindow(m_hWnd)); + if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) + return false; + if(!m_bPaintLabel) + return false; + + CClientDC dc(m_hWnd); + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcAll = rcClient; + + if(IsUsingTags()) + { + // find tags and label parts + LPTSTR lpstrLeft = NULL; + int cchLeft = 0; + LPTSTR lpstrLink = NULL; + int cchLink = 0; + LPTSTR lpstrRight = NULL; + int cchRight = 0; + + const T* pT = static_cast(this); + pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); + + // get label part rects + HFONT hFontOld = dc.SelectFont(m_hFontNormal); + RECT rcLeft = rcClient; + dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); + + dc.SelectFont(m_hFont); + RECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right, rcClient.bottom }; + dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); + + dc.SelectFont(m_hFontNormal); + RECT rcRight = { rcLink.right, rcLink.top, rcClient.right, rcClient.bottom }; + dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); + + dc.SelectFont(hFontOld); + + int cyMax = max(rcLeft.bottom, max(rcLink.bottom, rcRight.bottom)); + ::SetRect(&rcAll, rcLeft.left, rcLeft.top, rcRight.right, cyMax); + } + else + { + HFONT hOldFont = NULL; + if(m_hFont != NULL) + hOldFont = dc.SelectFont(m_hFont); + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + DWORD dwStyle = GetStyle(); + int nDrawStyle = DT_LEFT; + if (dwStyle & SS_CENTER) + nDrawStyle = DT_CENTER; + else if (dwStyle & SS_RIGHT) + nDrawStyle = DT_RIGHT; + dc.DrawText(lpstrText, -1, &rcAll, nDrawStyle | DT_WORDBREAK | DT_CALCRECT); + if(m_hFont != NULL) + dc.SelectFont(hOldFont); + if (dwStyle & SS_CENTER) + { + int dx = (rcClient.right - rcAll.right) / 2; + ::OffsetRect(&rcAll, dx, 0); + } + else if (dwStyle & SS_RIGHT) + { + int dx = rcClient.right - rcAll.right; + ::OffsetRect(&rcAll, dx, 0); + } + } + + cx = rcAll.right - rcAll.left; + cy = rcAll.bottom - rcAll.top; + + return true; + } + + // for command buttons only + bool GetToolTipText(LPTSTR lpstrBuffer, int nLength) const + { + ATLASSERT(IsCommandButton()); + return GetHyperLink(lpstrBuffer, nLength); + } + + bool SetToolTipText(LPCTSTR lpstrToolTipText) + { + ATLASSERT(IsCommandButton()); + return SetHyperLink(lpstrToolTipText); + } + +// Operations + BOOL SubclassWindow(HWND hWnd) + { + ATLASSERT(m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); +#if (_MSC_VER >= 1300) + BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWindow(hWnd); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass; + BOOL bRet = _baseClass::SubclassWindow(hWnd); +#endif // !(_MSC_VER >= 1300) + if(bRet) + { + T* pT = static_cast(this); + pT->Init(); + } + return bRet; + } + + bool Navigate() + { + ATLASSERT(::IsWindow(m_hWnd)); + bool bRet = true; + if(IsNotifyButton()) + { + NMHDR nmhdr = { m_hWnd, GetDlgCtrlID(), NM_CLICK }; + ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr); + } + else if(IsCommandButton()) + { + ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); + } + else + { + ATLASSERT(m_lpstrHyperLink != NULL); +#ifndef _WIN32_WCE + DWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T("open"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL); + bRet = (dwRet > 32); +#else // CE specific + SHELLEXECUTEINFO shExeInfo = { sizeof(SHELLEXECUTEINFO), 0, 0, L"open", m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL, 0, 0, 0, 0, 0, 0, 0 }; + ::ShellExecuteEx(&shExeInfo); + DWORD_PTR dwRet = (DWORD_PTR)shExeInfo.hInstApp; + bRet = (dwRet == 0) || (dwRet > 32); +#endif // _WIN32_WCE + ATLASSERT(bRet); + if(bRet) + { + m_bVisited = true; + Invalidate(); + } + } + return bRet; + } + +// Message map and handlers + BEGIN_MSG_MAP(CHyperLinkImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_SETFOCUS, OnFocus) + MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_CHAR, OnChar) + MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) + MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) + MESSAGE_HANDLER(WM_ENABLE, OnEnable) + MESSAGE_HANDLER(WM_GETFONT, OnGetFont) + MESSAGE_HANDLER(WM_SETFONT, OnSetFont) + MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState) + MESSAGE_HANDLER(WM_SIZE, OnSize) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->Init(); + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_tip.IsWindow()) + { + m_tip.DestroyWindow(); + m_tip.m_hWnd = NULL; + } + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + MSG msg = { m_hWnd, uMsg, wParam, lParam }; + if(m_tip.IsWindow() && IsUsingToolTip()) + m_tip.RelayEvent(&msg); + bHandled = FALSE; + return 1; + } +#endif // !_WIN32_WCE + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background painting needed (we do it all during WM_PAINT) + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(!m_bPaintLabel) + { + bHandled = FALSE; + return 1; + } + + T* pT = static_cast(this); + if(wParam != NULL) + { + pT->DoEraseBackground((HDC)wParam); + pT->DoPaint((HDC)wParam); + } + else + { + CPaintDC dc(m_hWnd); + pT->DoEraseBackground(dc.m_hDC); + pT->DoPaint(dc.m_hDC); + } + + return 0; + } + + LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bPaintLabel) + Invalidate(); + else + bHandled = FALSE; + return 0; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt)) + { + ::SetCursor(m_hCursor); + if(IsUnderlineHover()) + { + if(!m_bHover) + { + m_bHover = true; + InvalidateRect(&m_rcLink); + UpdateWindow(); +#ifndef _WIN32_WCE + StartTrackMouseLeave(); +#endif // !_WIN32_WCE + } + } + } + else + { + if(IsUnderlineHover()) + { + if(m_bHover) + { + m_bHover = false; + InvalidateRect(&m_rcLink); + UpdateWindow(); + } + } + bHandled = FALSE; + } + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(IsUnderlineHover() && m_bHover) + { + m_bHover = false; + InvalidateRect(&m_rcLink); + UpdateWindow(); + } + return 0; + } +#endif // !_WIN32_WCE + + LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if(::PtInRect(&m_rcLink, pt)) + { + SetFocus(); + SetCapture(); + } + return 0; + } + + LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + if(GetCapture() == m_hWnd) + { + ReleaseCapture(); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if(::PtInRect(&m_rcLink, pt)) + { + T* pT = static_cast(this); + pT->Navigate(); + } + } + return 0; + } + + LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(wParam == VK_RETURN || wParam == VK_SPACE) + { + T* pT = static_cast(this); + pT->Navigate(); + } + return 0; + } + + LRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return DLGC_WANTCHARS; + } + + LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + POINT pt = { 0, 0 }; + GetCursorPos(&pt); + ScreenToClient(&pt); + if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt)) + { + return TRUE; + } + bHandled = FALSE; + return FALSE; + } + + LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + Invalidate(); + UpdateWindow(); + return 0; + } + + LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)m_hFontNormal; + } + + LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + m_hFontNormal = (HFONT)wParam; + if((BOOL)lParam) + { + Invalidate(); + UpdateWindow(); + } + return 0; + } + + LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + // If the control is subclassed or superclassed, this message can cause + // repainting without WM_PAINT. We don't use this state, so just do nothing. + return 0; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->CalcLabelRect(); + pT->Invalidate(); + return 0; + } + +// Implementation + void Init() + { + ATLASSERT(::IsWindow(m_hWnd)); + + // Check if we should paint a label + const int cchBuff = 8; + TCHAR szBuffer[cchBuff] = { 0 }; + if(::GetClassName(m_hWnd, szBuffer, cchBuff)) + { + if(lstrcmpi(szBuffer, _T("static")) == 0) + { + ModifyStyle(0, SS_NOTIFY); // we need this + DWORD dwStyle = GetStyle() & 0x000000FF; +#ifndef _WIN32_WCE + if(dwStyle == SS_ICON || dwStyle == SS_BLACKRECT || dwStyle == SS_GRAYRECT || + dwStyle == SS_WHITERECT || dwStyle == SS_BLACKFRAME || dwStyle == SS_GRAYFRAME || + dwStyle == SS_WHITEFRAME || dwStyle == SS_OWNERDRAW || + dwStyle == SS_BITMAP || dwStyle == SS_ENHMETAFILE) +#else // CE specific + if(dwStyle == SS_ICON || dwStyle == SS_BITMAP) +#endif // _WIN32_WCE + m_bPaintLabel = false; + } + } + + // create or load a cursor +#if (WINVER >= 0x0500) || defined(_WIN32_WCE) + m_hCursor = ::LoadCursor(NULL, IDC_HAND); +#else + m_hCursor = ::CreateCursor(ModuleHelper::GetModuleInstance(), _AtlHyperLink_CursorData.xHotSpot, _AtlHyperLink_CursorData.yHotSpot, _AtlHyperLink_CursorData.cxWidth, _AtlHyperLink_CursorData.cyHeight, _AtlHyperLink_CursorData.arrANDPlane, _AtlHyperLink_CursorData.arrXORPlane); +#endif + ATLASSERT(m_hCursor != NULL); + + // set font + if(m_bPaintLabel) + { + ATL::CWindow wnd = GetParent(); + m_hFontNormal = wnd.GetFont(); + if(m_hFontNormal == NULL) + m_hFontNormal = (HFONT)::GetStockObject(SYSTEM_FONT); + if(m_hFontNormal != NULL && m_hFont == NULL) + { + LOGFONT lf = { 0 }; + CFontHandle font = m_hFontNormal; + font.GetLogFont(&lf); + if(IsUsingTagsBold()) + lf.lfWeight = FW_BOLD; + else if(!IsNotUnderlined()) + lf.lfUnderline = TRUE; + m_hFont = ::CreateFontIndirect(&lf); + m_bInternalLinkFont = true; + ATLASSERT(m_hFont != NULL); + } + } + +#ifndef _WIN32_WCE + // create a tool tip + m_tip.Create(m_hWnd); + ATLASSERT(m_tip.IsWindow()); +#endif // !_WIN32_WCE + + // set label (defaults to window text) + if(m_lpstrLabel == NULL) + { + int nLen = GetWindowTextLength(); + if(nLen > 0) + { + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(nLen + 1); + ATLASSERT(lpstrText != NULL); + if((lpstrText != NULL) && (GetWindowText(lpstrText, nLen + 1) > 0)) + SetLabel(lpstrText); + } + } + + T* pT = static_cast(this); + pT->CalcLabelRect(); + + // set hyperlink (defaults to label), or just activate tool tip if already set + if(m_lpstrHyperLink == NULL && !IsCommandButton()) + { + if(m_lpstrLabel != NULL) + SetHyperLink(m_lpstrLabel); + } +#ifndef _WIN32_WCE + else + { + m_tip.Activate(TRUE); + m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1); + } +#endif // !_WIN32_WCE + + // set link colors + if(m_bPaintLabel) + { + ATL::CRegKey rk; + LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Explorer\\Settings")); + if(lRet == 0) + { + const int cchValue = 12; + TCHAR szValue[cchValue] = { 0 }; +#if (_ATL_VER >= 0x0700) + ULONG ulCount = cchValue; + lRet = rk.QueryStringValue(_T("Anchor Color"), szValue, &ulCount); +#else + DWORD dwCount = cchValue * sizeof(TCHAR); + lRet = rk.QueryValue(szValue, _T("Anchor Color"), &dwCount); +#endif + if(lRet == 0) + { + COLORREF clr = pT->_ParseColorString(szValue); + ATLASSERT(clr != CLR_INVALID); + if(clr != CLR_INVALID) + m_clrLink = clr; + } + +#if (_ATL_VER >= 0x0700) + ulCount = cchValue; + lRet = rk.QueryStringValue(_T("Anchor Color Visited"), szValue, &ulCount); +#else + dwCount = cchValue * sizeof(TCHAR); + lRet = rk.QueryValue(szValue, _T("Anchor Color Visited"), &dwCount); +#endif + if(lRet == 0) + { + COLORREF clr = pT->_ParseColorString(szValue); + ATLASSERT(clr != CLR_INVALID); + if(clr != CLR_INVALID) + m_clrVisited = clr; + } + } + } + } + + static COLORREF _ParseColorString(LPTSTR lpstr) + { + int c[3] = { -1, -1, -1 }; + LPTSTR p = NULL; + for(int i = 0; i < 2; i++) + { + for(p = lpstr; *p != _T('\0'); p = ::CharNext(p)) + { + if(*p == _T(',')) + { + *p = _T('\0'); + c[i] = T::_xttoi(lpstr); + lpstr = &p[1]; + break; + } + } + if(c[i] == -1) + return CLR_INVALID; + } + if(*lpstr == _T('\0')) + return CLR_INVALID; + c[2] = T::_xttoi(lpstr); + + return RGB(c[0], c[1], c[2]); + } + + bool CalcLabelRect() + { + if(!::IsWindow(m_hWnd)) + return false; + if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) + return false; + + CClientDC dc(m_hWnd); + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + m_rcLink = rcClient; + if(!m_bPaintLabel) + return true; + + if(IsUsingTags()) + { + // find tags and label parts + LPTSTR lpstrLeft = NULL; + int cchLeft = 0; + LPTSTR lpstrLink = NULL; + int cchLink = 0; + LPTSTR lpstrRight = NULL; + int cchRight = 0; + + T* pT = static_cast(this); + pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); + ATLASSERT(lpstrLink != NULL); + ATLASSERT(cchLink > 0); + + // get label part rects + HFONT hFontOld = dc.SelectFont(m_hFontNormal); + + RECT rcLeft = rcClient; + if(lpstrLeft != NULL) + dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); + + dc.SelectFont(m_hFont); + RECT rcLink = rcClient; + if(lpstrLeft != NULL) + rcLink.left = rcLeft.right; + dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); + + dc.SelectFont(hFontOld); + + m_rcLink = rcLink; + } + else + { + HFONT hOldFont = NULL; + if(m_hFont != NULL) + hOldFont = dc.SelectFont(m_hFont); + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + DWORD dwStyle = GetStyle(); + int nDrawStyle = DT_LEFT; + if (dwStyle & SS_CENTER) + nDrawStyle = DT_CENTER; + else if (dwStyle & SS_RIGHT) + nDrawStyle = DT_RIGHT; + dc.DrawText(lpstrText, -1, &m_rcLink, nDrawStyle | DT_WORDBREAK | DT_CALCRECT); + if(m_hFont != NULL) + dc.SelectFont(hOldFont); + if (dwStyle & SS_CENTER) + { + int dx = (rcClient.right - m_rcLink.right) / 2; + ::OffsetRect(&m_rcLink, dx, 0); + } + else if (dwStyle & SS_RIGHT) + { + int dx = rcClient.right - m_rcLink.right; + ::OffsetRect(&m_rcLink, dx, 0); + } + } + + return true; + } + + void CalcLabelParts(LPTSTR& lpstrLeft, int& cchLeft, LPTSTR& lpstrLink, int& cchLink, LPTSTR& lpstrRight, int& cchRight) const + { + lpstrLeft = NULL; + cchLeft = 0; + lpstrLink = NULL; + cchLink = 0; + lpstrRight = NULL; + cchRight = 0; + + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + int cchText = lstrlen(lpstrText); + bool bOutsideLink = true; + for(int i = 0; i < cchText; i++) + { + if(lpstrText[i] != _T('<')) + continue; + + if(bOutsideLink) + { + if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 3, _T(""), 3) == CSTR_EQUAL) + { + if(i > 0) + { + lpstrLeft = lpstrText; + cchLeft = i; + } + lpstrLink = &lpstrText[i + 3]; + bOutsideLink = false; + } + } + else + { + if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 4, _T(""), 4) == CSTR_EQUAL) + { + cchLink = i - 3 - cchLeft; + if(lpstrText[i + 4] != 0) + { + lpstrRight = &lpstrText[i + 4]; + cchRight = cchText - (i + 4); + break; + } + } + } + } + + } + + void DoEraseBackground(CDCHandle dc) + { + HBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(), WM_CTLCOLORSTATIC, (WPARAM)dc.m_hDC, (LPARAM)m_hWnd); + if(hBrush != NULL) + { + RECT rect = { 0 }; + GetClientRect(&rect); + dc.FillRect(&rect, hBrush); + } + } + + void DoPaint(CDCHandle dc) + { + if(IsUsingTags()) + { + // find tags and label parts + LPTSTR lpstrLeft = NULL; + int cchLeft = 0; + LPTSTR lpstrLink = NULL; + int cchLink = 0; + LPTSTR lpstrRight = NULL; + int cchRight = 0; + + T* pT = static_cast(this); + pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); + + // get label part rects + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + + dc.SetBkMode(TRANSPARENT); + HFONT hFontOld = dc.SelectFont(m_hFontNormal); + + if(lpstrLeft != NULL) + dc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LEFT | DT_WORDBREAK); + + COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT))); + if(m_hFont != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) + dc.SelectFont(m_hFont); + else + dc.SelectFont(m_hFontNormal); + + dc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | DT_WORDBREAK); + + dc.SetTextColor(clrOld); + dc.SelectFont(m_hFontNormal); + if(lpstrRight != NULL) + { + RECT rcRight = { m_rcLink.right, m_rcLink.top, rcClient.right, rcClient.bottom }; + dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | DT_WORDBREAK); + } + + if(GetFocus() == m_hWnd) + dc.DrawFocusRect(&m_rcLink); + + dc.SelectFont(hFontOld); + } + else + { + dc.SetBkMode(TRANSPARENT); + COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT))); + + HFONT hFontOld = NULL; + if(m_hFont != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) + hFontOld = dc.SelectFont(m_hFont); + else + hFontOld = dc.SelectFont(m_hFontNormal); + + LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; + + DWORD dwStyle = GetStyle(); + int nDrawStyle = DT_LEFT; + if (dwStyle & SS_CENTER) + nDrawStyle = DT_CENTER; + else if (dwStyle & SS_RIGHT) + nDrawStyle = DT_RIGHT; + + dc.DrawText(lpstrText, -1, &m_rcLink, nDrawStyle | DT_WORDBREAK); + + if(GetFocus() == m_hWnd) + dc.DrawFocusRect(&m_rcLink); + + dc.SetTextColor(clrOld); + dc.SelectFont(hFontOld); + } + } + +#ifndef _WIN32_WCE + BOOL StartTrackMouseLeave() + { + TRACKMOUSEEVENT tme = { 0 }; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = m_hWnd; + return _TrackMouseEvent(&tme); + } +#endif // !_WIN32_WCE + +// Implementation helpers + bool IsUnderlined() const + { + return ((m_dwExtendedStyle & (HLINK_NOTUNDERLINED | HLINK_UNDERLINEHOVER)) == 0); + } + + bool IsNotUnderlined() const + { + return ((m_dwExtendedStyle & HLINK_NOTUNDERLINED) != 0); + } + + bool IsUnderlineHover() const + { + return ((m_dwExtendedStyle & HLINK_UNDERLINEHOVER) != 0); + } + + bool IsCommandButton() const + { + return ((m_dwExtendedStyle & HLINK_COMMANDBUTTON) != 0); + } + + bool IsNotifyButton() const + { + return ((m_dwExtendedStyle & HLINK_NOTIFYBUTTON) == HLINK_NOTIFYBUTTON); + } + + bool IsUsingTags() const + { + return ((m_dwExtendedStyle & HLINK_USETAGS) != 0); + } + + bool IsUsingTagsBold() const + { + return ((m_dwExtendedStyle & HLINK_USETAGSBOLD) == HLINK_USETAGSBOLD); + } + + bool IsUsingToolTip() const + { + return ((m_dwExtendedStyle & HLINK_NOTOOLTIP) == 0); + } + + static int _xttoi(const TCHAR* nptr) + { +#ifndef _ATL_MIN_CRT + return _ttoi(nptr); +#else // _ATL_MIN_CRT + while(*nptr == _T(' ')) // skip spaces + ++nptr; + + int c = (int)(_TUCHAR)*nptr++; + int sign = c; // save sign indication + if (c == _T('-') || c == _T('+')) + c = (int)(_TUCHAR)*nptr++; // skip sign + + int total = 0; + while((TCHAR)c >= _T('0') && (TCHAR)c <= _T('9')) + { + total = 10 * total + ((TCHAR)c - _T('0')); // accumulate digit + c = (int)(_TUCHAR)*nptr++; // get next char + } + + // return result, negated if necessary + return ((TCHAR)sign != _T('-')) ? total : -total; +#endif // _ATL_MIN_CRT + } +}; + + +class CHyperLink : public CHyperLinkImpl +{ +public: + DECLARE_WND_CLASS(_T("WTL_HyperLink")) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWaitCursor - displays a wait cursor + +class CWaitCursor +{ +public: +// Data + HCURSOR m_hWaitCursor; + HCURSOR m_hOldCursor; + bool m_bInUse; + +// Constructor/destructor + CWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false) + { + HINSTANCE hInstance = bSys ? NULL : ModuleHelper::GetResourceInstance(); + m_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor); + ATLASSERT(m_hWaitCursor != NULL); + + if(bSet) + Set(); + } + + ~CWaitCursor() + { + Restore(); + } + +// Methods + bool Set() + { + if(m_bInUse) + return false; + m_hOldCursor = ::SetCursor(m_hWaitCursor); + m_bInUse = true; + return true; + } + + bool Restore() + { + if(!m_bInUse) + return false; + ::SetCursor(m_hOldCursor); + m_bInUse = false; + return true; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CCustomWaitCursor - for custom and animated cursors + +class CCustomWaitCursor : public CWaitCursor +{ +public: +// Constructor/destructor + CCustomWaitCursor(ATL::_U_STRINGorID cursor, bool bSet = true, HINSTANCE hInstance = NULL) : + CWaitCursor(false, IDC_WAIT, true) + { + if(hInstance == NULL) + hInstance = ModuleHelper::GetResourceInstance(); + m_hWaitCursor = (HCURSOR)::LoadImage(hInstance, cursor.m_lpstr, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); + + if(bSet) + Set(); + } + + ~CCustomWaitCursor() + { + Restore(); +#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + ::DestroyCursor(m_hWaitCursor); +#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CMultiPaneStatusBarCtrl - Status Bar with multiple panes + +template +class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public ATL::CWindowImpl< T, TBase > +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + +// Data + enum { m_cxPaneMargin = 3 }; + + int m_nPanes; + int* m_pPane; + +// Constructor/destructor + CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL) + { } + + ~CMultiPaneStatusBarCtrlImpl() + { + delete [] m_pPane; + } + +// Methods + HWND Create(HWND hWndParent, LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) + { +#if (_MSC_VER >= 1300) + return ATL::CWindowImpl< T, TBase >::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase > _baseClass; + return _baseClass::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID); +#endif // !(_MSC_VER >= 1300) + } + + HWND Create(HWND hWndParent, UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) + { + const int cchMax = 128; // max text length is 127 for status bars (+1 for null) + TCHAR szText[cchMax]; + szText[0] = 0; + ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); + return Create(hWndParent, szText, dwStyle, nID); + } + + BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPanes > 0); + + m_nPanes = nPanes; + delete [] m_pPane; + m_pPane = NULL; + + ATLTRY(m_pPane = new int[nPanes]); + ATLASSERT(m_pPane != NULL); + if(m_pPane == NULL) + return FALSE; + + CTempBuffer buff; + int* pPanesPos = buff.Allocate(nPanes); + ATLASSERT(pPanesPos != NULL); + if(pPanesPos == NULL) + return FALSE; + + SecureHelper::memcpy_x(m_pPane, nPanes * sizeof(int), pPanes, nPanes * sizeof(int)); + + // get status bar DC and set font + CClientDC dc(m_hWnd); + HFONT hOldFont = dc.SelectFont(GetFont()); + + // get status bar borders + int arrBorders[3] = { 0 }; + GetBorders(arrBorders); + + const int cchBuff = 128; + TCHAR szBuff[cchBuff] = { 0 }; + SIZE size = { 0, 0 }; + int cxLeft = arrBorders[0]; + + // calculate right edge of each part + for(int i = 0; i < nPanes; i++) + { + if(pPanes[i] == ID_DEFAULT_PANE) + { + // make very large, will be resized later + pPanesPos[i] = INT_MAX / 2; + } + else + { + ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff); + dc.GetTextExtent(szBuff, lstrlen(szBuff), &size); + T* pT = static_cast(this); + pT; + pPanesPos[i] = cxLeft + size.cx + arrBorders[2] + 2 * pT->m_cxPaneMargin; + } + cxLeft = pPanesPos[i]; + } + + BOOL bRet = SetParts(nPanes, pPanesPos); + + if(bRet && bSetText) + { + for(int i = 0; i < nPanes; i++) + { + if(pPanes[i] != ID_DEFAULT_PANE) + { + ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff); + SetPaneText(m_pPane[i], szBuff); + } + } + } + + dc.SelectFont(hOldFont); + return bRet; + } + + bool GetPaneTextLength(int nPaneID, int* pcchLength = NULL, int* pnType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return false; + + int nLength = GetTextLength(nIndex, pnType); + if(pcchLength != NULL) + *pcchLength = nLength; + + return true; + } + + BOOL GetPaneText(int nPaneID, LPTSTR lpstrText, int* pcchLength = NULL, int* pnType = NULL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + int nLength = GetText(nIndex, lpstrText, pnType); + if(pcchLength != NULL) + *pcchLength = nLength; + + return TRUE; + } + + BOOL SetPaneText(int nPaneID, LPCTSTR lpstrText, int nType = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + return SetText(nIndex, lpstrText, nType); + } + + BOOL GetPaneRect(int nPaneID, LPRECT lpRect) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + return GetRect(nIndex, lpRect); + } + + BOOL SetPaneWidth(int nPaneID, int cxWidth) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPaneID != ID_DEFAULT_PANE); // Can't resize this one + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + // get pane positions + CTempBuffer buff; + int* pPanesPos = buff.Allocate(m_nPanes); + if(pPanesPos == NULL) + return FALSE; + GetParts(m_nPanes, pPanesPos); + // calculate offset + int cxPaneWidth = pPanesPos[nIndex] - ((nIndex == 0) ? 0 : pPanesPos[nIndex - 1]); + int cxOff = cxWidth - cxPaneWidth; + // find variable width pane + int nDef = m_nPanes; + for(int i = 0; i < m_nPanes; i++) + { + if(m_pPane[i] == ID_DEFAULT_PANE) + { + nDef = i; + break; + } + } + // resize + if(nIndex < nDef) // before default pane + { + for(int i = nIndex; i < nDef; i++) + pPanesPos[i] += cxOff; + + } + else // after default one + { + for(int i = nDef; i < nIndex; i++) + pPanesPos[i] -= cxOff; + } + // set pane postions + return SetParts(m_nPanes, pPanesPos); + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + BOOL GetPaneTipText(int nPaneID, LPTSTR lpstrText, int nSize) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + GetTipText(nIndex, lpstrText, nSize); + return TRUE; + } + + BOOL SetPaneTipText(int nPaneID, LPCTSTR lpstrText) + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + SetTipText(nIndex, lpstrText); + return TRUE; + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +#if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) + BOOL GetPaneIcon(int nPaneID, HICON& hIcon) const + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + hIcon = GetIcon(nIndex); + return TRUE; + } + + BOOL SetPaneIcon(int nPaneID, HICON hIcon) + { + ATLASSERT(::IsWindow(m_hWnd)); + int nIndex = GetPaneIndexFromID(nPaneID); + if(nIndex == -1) + return FALSE; + + return SetIcon(nIndex, hIcon); + } +#endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) + +// Message map and handlers + BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl< T >) + MESSAGE_HANDLER(WM_SIZE, OnSize) + END_MSG_MAP() + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + if(wParam != SIZE_MINIMIZED && m_nPanes > 0) + { + T* pT = static_cast(this); + pT->UpdatePanesLayout(); + } + return lRet; + } + +// Implementation + BOOL UpdatePanesLayout() + { + // get pane positions + CTempBuffer buff; + int* pPanesPos = buff.Allocate(m_nPanes); + ATLASSERT(pPanesPos != NULL); + if(pPanesPos == NULL) + return FALSE; + int nRet = GetParts(m_nPanes, pPanesPos); + ATLASSERT(nRet == m_nPanes); + if(nRet != m_nPanes) + return FALSE; + // calculate offset + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + int cxOff = rcClient.right - pPanesPos[m_nPanes - 1]; +#ifndef _WIN32_WCE + // Move panes left if size grip box is present + if((GetStyle() & SBARS_SIZEGRIP) != 0) + cxOff -= ::GetSystemMetrics(SM_CXVSCROLL) + ::GetSystemMetrics(SM_CXEDGE); +#endif // !_WIN32_WCE + // find variable width pane + int i; + for(i = 0; i < m_nPanes; i++) + { + if(m_pPane[i] == ID_DEFAULT_PANE) + break; + } + // resize all panes from the variable one to the right + if((i < m_nPanes) && (pPanesPos[i] + cxOff) > ((i == 0) ? 0 : pPanesPos[i - 1])) + { + for(; i < m_nPanes; i++) + pPanesPos[i] += cxOff; + } + // set pane postions + return SetParts(m_nPanes, pPanesPos); + } + + int GetPaneIndexFromID(int nPaneID) const + { + for(int i = 0; i < m_nPanes; i++) + { + if(m_pPane[i] == nPaneID) + return i; + } + + return -1; // not found + } +}; + +class CMultiPaneStatusBarCtrl : public CMultiPaneStatusBarCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName()) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPaneContainer - provides header with title and close button for panes + +// pane container extended styles +#define PANECNT_NOCLOSEBUTTON 0x00000001 +#define PANECNT_VERTICAL 0x00000002 +#define PANECNT_FLATBORDER 0x00000004 +#define PANECNT_NOBORDER 0x00000008 + +template +class ATL_NO_VTABLE CPaneContainerImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CCustomDraw< T > +{ +public: + DECLARE_WND_CLASS_EX(NULL, 0, -1) + +// Constants + enum + { + m_cxyBorder = 2, + m_cxyTextOffset = 4, + m_cxyBtnOffset = 1, + + m_cchTitle = 80, + + m_cxImageTB = 13, + m_cyImageTB = 11, + m_cxyBtnAddTB = 7, + + m_cxToolBar = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + m_cxyBtnOffset, + + m_xBtnImageLeft = 6, + m_yBtnImageTop = 5, + m_xBtnImageRight = 12, + m_yBtnImageBottom = 11, + + m_nCloseBtnID = ID_PANE_CLOSE + }; + +// Data members + CToolBarCtrl m_tb; + ATL::CWindow m_wndClient; + int m_cxyHeader; + TCHAR m_szTitle[m_cchTitle]; + DWORD m_dwExtendedStyle; // Pane container specific extended styles + + +// Constructor + CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0) + { + m_szTitle[0] = 0; + } + +// Attributes + DWORD GetPaneContainerExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + if(m_hWnd != NULL) + { + T* pT = static_cast(this); + bool bUpdate = false; + + if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) != 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)) // add close button + { + pT->CreateCloseButton(); + bUpdate = true; + } + else if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) == 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) != 0)) // remove close button + { + pT->DestroyCloseButton(); + bUpdate = true; + } + + if((dwPrevStyle & PANECNT_VERTICAL) != (m_dwExtendedStyle & PANECNT_VERTICAL)) // change orientation + { + pT->CalcSize(); + bUpdate = true; + } + + if((dwPrevStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER)) != + (m_dwExtendedStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER))) // change border + { + bUpdate = true; + } + + if(bUpdate) + pT->UpdateLayout(); + } + return dwPrevStyle; + } + + HWND GetClient() const + { + return m_wndClient; + } + + HWND SetClient(HWND hWndClient) + { + HWND hWndOldClient = m_wndClient; + m_wndClient = hWndClient; + if(m_hWnd != NULL) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + return hWndOldClient; + } + + BOOL GetTitle(LPTSTR lpstrTitle, int cchLength) const + { + ATLASSERT(lpstrTitle != NULL); + + errno_t nRet = SecureHelper::strncpy_x(lpstrTitle, cchLength, m_szTitle, _TRUNCATE); + + return (nRet == 0 || nRet == STRUNCATE); + } + + BOOL SetTitle(LPCTSTR lpstrTitle) + { + ATLASSERT(lpstrTitle != NULL); + + errno_t nRet = SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE); + bool bRet = (nRet == 0 || nRet == STRUNCATE); + if(bRet && m_hWnd != NULL) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + + return bRet; + } + + int GetTitleLength() const + { + return lstrlen(m_szTitle); + } + +// Methods + HWND Create(HWND hWndParent, LPCTSTR lpstrTitle = NULL, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) + { + if(lpstrTitle != NULL) + SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE); +#if (_MSC_VER >= 1300) + return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); +#endif // !(_MSC_VER >= 1300) + } + + HWND Create(HWND hWndParent, UINT uTitleID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) + { + if(uTitleID != 0U) + ::LoadString(ModuleHelper::GetResourceInstance(), uTitleID, m_szTitle, m_cchTitle); +#if (_MSC_VER >= 1300) + return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); +#else // !(_MSC_VER >= 1300) + typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; + return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); +#endif // !(_MSC_VER >= 1300) + } + + BOOL EnableCloseButton(BOOL bEnable) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT; // avoid level 4 warning + return (m_tb.m_hWnd != NULL) ? m_tb.EnableButton(pT->m_nCloseBtnID, bEnable) : FALSE; + } + + void UpdateLayout() + { + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + T* pT = static_cast(this); + pT->UpdateLayout(rcClient.right, rcClient.bottom); + } + +// Message map and handlers + BEGIN_MSG_MAP(CPaneContainerImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_NOTIFY, OnNotify) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + FORWARD_NOTIFICATIONS() + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->CalcSize(); + + if((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0) + pT->CreateCloseButton(); + + return 0; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + return 0; + } + + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_wndClient.m_hWnd != NULL) + m_wndClient.SetFocus(); + return 0; + } + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + if(wParam != NULL) + { + pT->DrawPaneTitle((HDC)wParam); + + if(m_wndClient.m_hWnd == NULL) // no client window + pT->DrawPane((HDC)wParam); + } + else + { + CPaintDC dc(m_hWnd); + pT->DrawPaneTitle(dc.m_hDC); + + if(m_wndClient.m_hWnd == NULL) // no client window + pT->DrawPane(dc.m_hDC); + } + + return 0; + } + + LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(m_tb.m_hWnd == NULL) + { + bHandled = FALSE; + return 1; + } + + T* pT = static_cast(this); + pT; + LPNMHDR lpnmh = (LPNMHDR)lParam; + LRESULT lRet = 0; + + // pass toolbar custom draw notifications to the base class + if(lpnmh->code == NM_CUSTOMDRAW && lpnmh->hwndFrom == m_tb.m_hWnd) + lRet = CCustomDraw< T >::OnCustomDraw(0, lpnmh, bHandled); +#ifndef _WIN32_WCE + // tooltip notifications come with the tooltip window handle and button ID, + // pass them to the parent if we don't handle them + else if(lpnmh->code == TTN_GETDISPINFO && lpnmh->idFrom == pT->m_nCloseBtnID) + bHandled = pT->GetToolTipText(lpnmh); +#endif // !_WIN32_WCE + // only let notifications not from the toolbar go to the parent + else if(lpnmh->hwndFrom != m_tb.m_hWnd && lpnmh->idFrom != pT->m_nCloseBtnID) + bHandled = FALSE; + + return lRet; + } + + LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + // if command comes from the close button, substitute HWND of the pane container instead + if(m_tb.m_hWnd != NULL && (HWND)lParam == m_tb.m_hWnd) + return ::SendMessage(GetParent(), WM_COMMAND, wParam, (LPARAM)m_hWnd); + + bHandled = FALSE; + return 1; + } + +// Custom draw overrides + DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) + { + return CDRF_NOTIFYITEMDRAW; // we need per-item notifications + } + + DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw) + { + CDCHandle dc = lpNMCustomDraw->hdc; +#if (_WIN32_IE >= 0x0400) + RECT& rc = lpNMCustomDraw->rc; +#else // !(_WIN32_IE >= 0x0400) + RECT rc; + m_tb.GetItemRect(0, &rc); +#endif // !(_WIN32_IE >= 0x0400) + + dc.FillRect(&rc, COLOR_3DFACE); + + return CDRF_NOTIFYPOSTPAINT; + } + + DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw) + { + CDCHandle dc = lpNMCustomDraw->hdc; +#if (_WIN32_IE >= 0x0400) + RECT& rc = lpNMCustomDraw->rc; +#else // !(_WIN32_IE >= 0x0400) + RECT rc = { 0 }; + m_tb.GetItemRect(0, &rc); +#endif // !(_WIN32_IE >= 0x0400) + + RECT rcImage = { m_xBtnImageLeft, m_yBtnImageTop, m_xBtnImageRight + 1, m_yBtnImageBottom + 1 }; + ::OffsetRect(&rcImage, rc.left, rc.top); + T* pT = static_cast(this); + + if((lpNMCustomDraw->uItemState & CDIS_DISABLED) != 0) + { + RECT rcShadow = rcImage; + ::OffsetRect(&rcShadow, 1, 1); + CPen pen1; + pen1.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT)); + pT->DrawButtonImage(dc, rcShadow, pen1); + CPen pen2; + pen2.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW)); + pT->DrawButtonImage(dc, rcImage, pen2); + } + else + { + if((lpNMCustomDraw->uItemState & CDIS_SELECTED) != 0) + ::OffsetRect(&rcImage, 1, 1); + CPen pen; + pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT)); + pT->DrawButtonImage(dc, rcImage, pen); + } + + return CDRF_DODEFAULT; // continue with the default item painting + } + +// Implementation - overrideable methods + void UpdateLayout(int cxWidth, int cyHeight) + { + ATLASSERT(::IsWindow(m_hWnd)); + RECT rect = { 0 }; + + if(IsVertical()) + { + ::SetRect(&rect, 0, 0, m_cxyHeader, cyHeight); + if(m_tb.m_hWnd != NULL) + m_tb.SetWindowPos(NULL, m_cxyBorder, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + + if(m_wndClient.m_hWnd != NULL) + m_wndClient.SetWindowPos(NULL, m_cxyHeader, 0, cxWidth - m_cxyHeader, cyHeight, SWP_NOZORDER); + else + rect.right = cxWidth; + } + else + { + ::SetRect(&rect, 0, 0, cxWidth, m_cxyHeader); + if(m_tb.m_hWnd != NULL) + m_tb.SetWindowPos(NULL, rect.right - m_cxToolBar, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + + if(m_wndClient.m_hWnd != NULL) + m_wndClient.SetWindowPos(NULL, 0, m_cxyHeader, cxWidth, cyHeight - m_cxyHeader, SWP_NOZORDER); + else + rect.bottom = cyHeight; + } + + InvalidateRect(&rect); + } + + void CreateCloseButton() + { + ATLASSERT(m_tb.m_hWnd == NULL); + // create toolbar for the "x" button + m_tb.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NOMOVEY | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT, 0); + ATLASSERT(m_tb.IsWindow()); + + if(m_tb.m_hWnd != NULL) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + + m_tb.SetButtonStructSize(); + + TBBUTTON tbbtn = { 0 }; + tbbtn.idCommand = pT->m_nCloseBtnID; + tbbtn.fsState = TBSTATE_ENABLED; + tbbtn.fsStyle = TBSTYLE_BUTTON; + m_tb.AddButtons(1, &tbbtn); + + m_tb.SetBitmapSize(m_cxImageTB, m_cyImageTB); + m_tb.SetButtonSize(m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB); + + if(IsVertical()) + m_tb.SetWindowPos(NULL, m_cxyBorder + m_cxyBtnOffset, m_cxyBorder + m_cxyBtnOffset, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB, SWP_NOZORDER | SWP_NOACTIVATE); + else + m_tb.SetWindowPos(NULL, 0, 0, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + } + } + + void DestroyCloseButton() + { + if(m_tb.m_hWnd != NULL) + m_tb.DestroyWindow(); + } + + void CalcSize() + { + T* pT = static_cast(this); + CFontHandle font = pT->GetTitleFont(); + LOGFONT lf = { 0 }; + font.GetLogFont(lf); + if(IsVertical()) + { + m_cxyHeader = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder; + } + else + { + int cyFont = abs(lf.lfHeight) + m_cxyBorder + 2 * m_cxyTextOffset; + int cyBtn = m_cyImageTB + m_cxyBtnAddTB + m_cxyBorder + 2 * m_cxyBtnOffset; + m_cxyHeader = max(cyFont, cyBtn); + } + } + + HFONT GetTitleFont() const + { + return AtlGetDefaultGuiFont(); + } + +#ifndef _WIN32_WCE + BOOL GetToolTipText(LPNMHDR /*lpnmh*/) + { + return FALSE; + } +#endif // !_WIN32_WCE + + void DrawPaneTitle(CDCHandle dc) + { + RECT rect = { 0 }; + GetClientRect(&rect); + + UINT uBorder = BF_LEFT | BF_TOP | BF_ADJUST; + if(IsVertical()) + { + rect.right = rect.left + m_cxyHeader; + uBorder |= BF_BOTTOM; + } + else + { + rect.bottom = rect.top + m_cxyHeader; + uBorder |= BF_RIGHT; + } + + if((m_dwExtendedStyle & PANECNT_NOBORDER) == 0) + { + if((m_dwExtendedStyle & PANECNT_FLATBORDER) != 0) + uBorder |= BF_FLAT; + dc.DrawEdge(&rect, EDGE_ETCHED, uBorder); + } + dc.FillRect(&rect, COLOR_3DFACE); + + if(!IsVertical()) // draw title only for horizontal pane container + { + dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); + dc.SetBkMode(TRANSPARENT); + T* pT = static_cast(this); + HFONT hFontOld = dc.SelectFont(pT->GetTitleFont()); + rect.left += m_cxyTextOffset; + rect.right -= m_cxyTextOffset; + if(m_tb.m_hWnd != NULL) + rect.right -= m_cxToolBar;; +#ifndef _WIN32_WCE + dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS); +#else // CE specific + dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER); +#endif // _WIN32_WCE + dc.SelectFont(hFontOld); + } + } + + // called only if pane is empty + void DrawPane(CDCHandle dc) + { + RECT rect = { 0 }; + GetClientRect(&rect); + if(IsVertical()) + rect.left += m_cxyHeader; + else + rect.top += m_cxyHeader; + if((GetExStyle() & WS_EX_CLIENTEDGE) == 0) + dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + dc.FillRect(&rect, COLOR_APPWORKSPACE); + } + + // drawing helper - draws "x" button image + void DrawButtonImage(CDCHandle dc, RECT& rcImage, HPEN hPen) + { +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + HPEN hPenOld = dc.SelectPen(hPen); + + dc.MoveTo(rcImage.left, rcImage.top); + dc.LineTo(rcImage.right, rcImage.bottom); + dc.MoveTo(rcImage.left + 1, rcImage.top); + dc.LineTo(rcImage.right + 1, rcImage.bottom); + + dc.MoveTo(rcImage.left, rcImage.bottom - 1); + dc.LineTo(rcImage.right, rcImage.top - 1); + dc.MoveTo(rcImage.left + 1, rcImage.bottom - 1); + dc.LineTo(rcImage.right + 1, rcImage.top - 1); + + dc.SelectPen(hPenOld); +#else // (_WIN32_WCE < 400) + rcImage; + hPen; + // no support for the "x" button image +#endif // (_WIN32_WCE < 400) + } + + bool IsVertical() const + { + return ((m_dwExtendedStyle & PANECNT_VERTICAL) != 0); + } +}; + +class CPaneContainer : public CPaneContainerImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CSortListViewCtrl - implements sorting for a listview control + +// sort listview extended styles +#define SORTLV_USESHELLBITMAPS 0x00000001 + +// Notification sent to parent when sort column is changed by user clicking header. +#define SLVN_SORTCHANGED LVN_LAST + +// A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification +typedef struct tagNMSORTLISTVIEW +{ + NMHDR hdr; + int iNewSortColumn; + int iOldSortColumn; +} NMSORTLISTVIEW, *LPNMSORTLISTVIEW; + +// Column sort types. Can be set on a per-column basis with the SetColumnSortType method. +enum +{ + LVCOLSORT_NONE, + LVCOLSORT_TEXT, // default + LVCOLSORT_TEXTNOCASE, + LVCOLSORT_LONG, + LVCOLSORT_DOUBLE, + LVCOLSORT_DECIMAL, + LVCOLSORT_DATETIME, + LVCOLSORT_DATE, + LVCOLSORT_TIME, + LVCOLSORT_CUSTOM, + LVCOLSORT_LAST = LVCOLSORT_CUSTOM +}; + + +template +class CSortListViewImpl +{ +public: + enum + { + m_cchCmpTextMax = 32, // overrideable + m_cxSortImage = 16, + m_cySortImage = 15, + m_cxSortArrow = 11, + m_cySortArrow = 6, + m_iSortUp = 0, // index of sort bitmaps + m_iSortDown = 1, + m_nShellSortUpID = 133 + }; + + // passed to LVCompare functions as lParam1 and lParam2 + struct LVCompareParam + { + int iItem; + DWORD_PTR dwItemData; + union + { + long lValue; + double dblValue; + DECIMAL decValue; + LPCTSTR pszValue; + }; + }; + + // passed to LVCompare functions as the lParamSort parameter + struct LVSortInfo + { + T* pT; + int iSortCol; + bool bDescending; + }; + + bool m_bSortDescending; + bool m_bCommCtrl6; + int m_iSortColumn; + CBitmap m_bmSort[2]; + int m_fmtOldSortCol; + HBITMAP m_hbmOldSortCol; + DWORD m_dwSortLVExtendedStyle; + ATL::CSimpleArray m_arrColSortType; + bool m_bUseWaitCursor; + + CSortListViewImpl() : + m_bSortDescending(false), + m_bCommCtrl6(false), + m_iSortColumn(-1), + m_fmtOldSortCol(0), + m_hbmOldSortCol(NULL), + m_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS), + m_bUseWaitCursor(true) + { +#ifndef _WIN32_WCE + DWORD dwMajor = 0; + DWORD dwMinor = 0; + HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); + m_bCommCtrl6 = SUCCEEDED(hRet) && dwMajor >= 6; +#endif // !_WIN32_WCE + } + +// Attributes + void SetSortColumn(int iCol) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + CHeaderCtrl header = pT->GetHeader(); + ATLASSERT(header.m_hWnd != NULL); + ATLASSERT(iCol >= -1 && iCol < m_arrColSortType.GetSize()); + + int iOldSortCol = m_iSortColumn; + m_iSortColumn = iCol; + if(m_bCommCtrl6) + { +#ifndef HDF_SORTUP + const int HDF_SORTUP = 0x0400; +#endif // HDF_SORTUP +#ifndef HDF_SORTDOWN + const int HDF_SORTDOWN = 0x0200; +#endif // HDF_SORTDOWN + const int nMask = HDF_SORTUP | HDF_SORTDOWN; + HDITEM hditem = { HDI_FORMAT }; + if(iOldSortCol != iCol && iOldSortCol >= 0 && header.GetItem(iOldSortCol, &hditem)) + { + hditem.fmt &= ~nMask; + header.SetItem(iOldSortCol, &hditem); + } + if(iCol >= 0 && header.GetItem(iCol, &hditem)) + { + hditem.fmt &= ~nMask; + hditem.fmt |= m_bSortDescending ? HDF_SORTDOWN : HDF_SORTUP; + header.SetItem(iCol, &hditem); + } + return; + } + + if(m_bmSort[m_iSortUp].IsNull()) + pT->CreateSortBitmaps(); + + // restore previous sort column's bitmap, if any, and format + HDITEM hditem = { HDI_BITMAP | HDI_FORMAT }; + if(iOldSortCol != iCol && iOldSortCol >= 0) + { + hditem.hbm = m_hbmOldSortCol; + hditem.fmt = m_fmtOldSortCol; + header.SetItem(iOldSortCol, &hditem); + } + + // save new sort column's bitmap and format, and add our sort bitmap + if(iCol >= 0 && header.GetItem(iCol, &hditem)) + { + if(iOldSortCol != iCol) + { + m_fmtOldSortCol = hditem.fmt; + m_hbmOldSortCol = hditem.hbm; + } + hditem.fmt &= ~HDF_IMAGE; + hditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT; + int i = m_bSortDescending ? m_iSortDown : m_iSortUp; + hditem.hbm = m_bmSort[i]; + header.SetItem(iCol, &hditem); + } + } + + int GetSortColumn() const + { + return m_iSortColumn; + } + + void SetColumnSortType(int iCol, WORD wType) + { + ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize()); + ATLASSERT(wType >= LVCOLSORT_NONE && wType <= LVCOLSORT_LAST); + m_arrColSortType[iCol] = wType; + } + + WORD GetColumnSortType(int iCol) const + { + ATLASSERT((iCol >= 0) && iCol < m_arrColSortType.GetSize()); + return m_arrColSortType[iCol]; + } + + int GetColumnCount() const + { + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + CHeaderCtrl header = pT->GetHeader(); + return header.m_hWnd != NULL ? header.GetItemCount() : 0; + } + + bool IsSortDescending() const + { + return m_bSortDescending; + } + + DWORD GetSortListViewExtendedStyle() const + { + return m_dwSortLVExtendedStyle; + } + + DWORD SetSortListViewExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwSortLVExtendedStyle; + if(dwMask == 0) + m_dwSortLVExtendedStyle = dwExtendedStyle; + else + m_dwSortLVExtendedStyle = (m_dwSortLVExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + return dwPrevStyle; + } + +// Operations + bool DoSortItems(int iCol, bool bDescending = false) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize()); + + WORD wType = m_arrColSortType[iCol]; + if(wType == LVCOLSORT_NONE) + return false; + + int nCount = pT->GetItemCount(); + if(nCount < 2) + { + m_bSortDescending = bDescending; + SetSortColumn(iCol); + return true; + } + + CWaitCursor waitCursor(false); + if(m_bUseWaitCursor) + waitCursor.Set(); + + LVCompareParam* pParam = NULL; + ATLTRY(pParam = new LVCompareParam[nCount]); + PFNLVCOMPARE pFunc = NULL; + TCHAR pszTemp[pT->m_cchCmpTextMax]; + bool bStrValue = false; + + switch(wType) + { + case LVCOLSORT_TEXT: + pFunc = (PFNLVCOMPARE)pT->LVCompareText; + case LVCOLSORT_TEXTNOCASE: + if(pFunc == NULL) + pFunc = (PFNLVCOMPARE)pT->LVCompareTextNoCase; + case LVCOLSORT_CUSTOM: + { + if(pFunc == NULL) + pFunc = (PFNLVCOMPARE)pT->LVCompareCustom; + + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pParam[i].pszValue = new TCHAR[pT->m_cchCmpTextMax]; + pT->GetItemText(i, iCol, (LPTSTR)pParam[i].pszValue, pT->m_cchCmpTextMax); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + bStrValue = true; + } + break; + case LVCOLSORT_LONG: + { + pFunc = (PFNLVCOMPARE)pT->LVCompareLong; + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); + pParam[i].lValue = pT->StrToLong(pszTemp); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + } + break; + case LVCOLSORT_DOUBLE: + { + pFunc = (PFNLVCOMPARE)pT->LVCompareDouble; + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); + pParam[i].dblValue = pT->StrToDouble(pszTemp); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + } + break; + case LVCOLSORT_DECIMAL: + { + pFunc = (PFNLVCOMPARE)pT->LVCompareDecimal; + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); + pT->StrToDecimal(pszTemp, &pParam[i].decValue); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + } + break; + case LVCOLSORT_DATETIME: + case LVCOLSORT_DATE: + case LVCOLSORT_TIME: + { + pFunc = (PFNLVCOMPARE)pT->LVCompareDouble; + DWORD dwFlags = LOCALE_NOUSEROVERRIDE; + if(wType == LVCOLSORT_DATE) + dwFlags |= VAR_DATEVALUEONLY; + else if(wType == LVCOLSORT_TIME) + dwFlags |= VAR_TIMEVALUEONLY; + for(int i = 0; i < nCount; i++) + { + pParam[i].iItem = i; + pParam[i].dwItemData = pT->GetItemData(i); + pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); + pParam[i].dblValue = pT->DateStrToDouble(pszTemp, dwFlags); + pT->SetItemData(i, (DWORD_PTR)&pParam[i]); + } + } + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("Unknown value for sort type in CSortListViewImpl::DoSortItems()\n")); + break; + } // switch(wType) + + ATLASSERT(pFunc != NULL); + LVSortInfo lvsi = { pT, iCol, bDescending }; + bool bRet = ((BOOL)pT->DefWindowProc(LVM_SORTITEMS, (WPARAM)&lvsi, (LPARAM)pFunc) != FALSE); + for(int i = 0; i < nCount; i++) + { + DWORD_PTR dwItemData = pT->GetItemData(i); + LVCompareParam* p = (LVCompareParam*)dwItemData; + ATLASSERT(p != NULL); + if(bStrValue) + delete [] (TCHAR*)p->pszValue; + pT->SetItemData(i, p->dwItemData); + } + delete [] pParam; + + if(bRet) + { + m_bSortDescending = bDescending; + SetSortColumn(iCol); + } + + if(m_bUseWaitCursor) + waitCursor.Restore(); + + return bRet; + } + + void CreateSortBitmaps() + { + if((m_dwSortLVExtendedStyle & SORTLV_USESHELLBITMAPS) != 0) + { + bool bFree = false; + LPCTSTR pszModule = _T("shell32.dll"); + HINSTANCE hShell = ::GetModuleHandle(pszModule); + + if (hShell == NULL) + { + hShell = ::LoadLibrary(pszModule); + bFree = true; + } + + if (hShell != NULL) + { + bool bSuccess = true; + for(int i = m_iSortUp; i <= m_iSortDown; i++) + { + if(!m_bmSort[i].IsNull()) + m_bmSort[i].DeleteObject(); + m_bmSort[i] = (HBITMAP)::LoadImage(hShell, MAKEINTRESOURCE(m_nShellSortUpID + i), +#ifndef _WIN32_WCE + IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); +#else // CE specific + IMAGE_BITMAP, 0, 0, 0); +#endif // _WIN32_WCE + if(m_bmSort[i].IsNull()) + { + bSuccess = false; + break; + } + } + if(bFree) + ::FreeLibrary(hShell); + if(bSuccess) + return; + } + } + + T* pT = static_cast(this); + for(int i = m_iSortUp; i <= m_iSortDown; i++) + { + if(!m_bmSort[i].IsNull()) + m_bmSort[i].DeleteObject(); + + CDC dcMem; + CClientDC dc(::GetDesktopWindow()); + dcMem.CreateCompatibleDC(dc.m_hDC); + m_bmSort[i].CreateCompatibleBitmap(dc.m_hDC, m_cxSortImage, m_cySortImage); + HBITMAP hbmOld = dcMem.SelectBitmap(m_bmSort[i]); + RECT rc = {0,0,m_cxSortImage, m_cySortImage}; + pT->DrawSortBitmap(dcMem.m_hDC, i, &rc); + dcMem.SelectBitmap(hbmOld); + dcMem.DeleteDC(); + } + } + + void NotifyParentSortChanged(int iNewSortCol, int iOldSortCol) + { + T* pT = static_cast(this); + int nID = pT->GetDlgCtrlID(); + NMSORTLISTVIEW nm = { { pT->m_hWnd, nID, SLVN_SORTCHANGED }, iNewSortCol, iOldSortCol }; + ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nm); + } + +// Overrideables + int CompareItemsCustom(LVCompareParam* /*pItem1*/, LVCompareParam* /*pItem2*/, int /*iSortCol*/) + { + // pItem1 and pItem2 contain valid iItem, dwItemData, and pszValue members. + // If item1 > item2 return 1, if item1 < item2 return -1, else return 0. + return 0; + } + + void DrawSortBitmap(CDCHandle dc, int iBitmap, LPRECT prc) + { + dc.FillRect(prc, ::GetSysColorBrush(COLOR_BTNFACE)); + HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW)); + CPen pen; + pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNSHADOW)); + HPEN hpenOld = dc.SelectPen(pen); + POINT ptOrg = { (m_cxSortImage - m_cxSortArrow) / 2, (m_cySortImage - m_cySortArrow) / 2 }; + if(iBitmap == m_iSortUp) + { + POINT pts[3] = + { + { ptOrg.x + m_cxSortArrow / 2, ptOrg.y }, + { ptOrg.x, ptOrg.y + m_cySortArrow - 1 }, + { ptOrg.x + m_cxSortArrow - 1, ptOrg.y + m_cySortArrow - 1 } + }; + dc.Polygon(pts, 3); + } + else + { + POINT pts[3] = + { + { ptOrg.x, ptOrg.y }, + { ptOrg.x + m_cxSortArrow / 2, ptOrg.y + m_cySortArrow - 1 }, + { ptOrg.x + m_cxSortArrow - 1, ptOrg.y } + }; + dc.Polygon(pts, 3); + } + dc.SelectBrush(hbrOld); + dc.SelectPen(hpenOld); + } + + double DateStrToDouble(LPCTSTR lpstr, DWORD dwFlags) + { + ATLASSERT(lpstr != NULL); + if(lpstr == NULL || lpstr[0] == _T('\0')) + return 0; + + USES_CONVERSION; + HRESULT hRet = E_FAIL; + DATE dRet = 0; + if (FAILED(hRet = ::VarDateFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, dwFlags, &dRet))) + { + ATLTRACE2(atlTraceUI, 0, _T("VarDateFromStr failed with result of 0x%8.8X\n"), hRet); + dRet = 0; + } + return dRet; + } + + long StrToLong(LPCTSTR lpstr) + { + ATLASSERT(lpstr != NULL); + if(lpstr == NULL || lpstr[0] == _T('\0')) + return 0; + + USES_CONVERSION; + HRESULT hRet = E_FAIL; + long lRet = 0; + if (FAILED(hRet = ::VarI4FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &lRet))) + { + ATLTRACE2(atlTraceUI, 0, _T("VarI4FromStr failed with result of 0x%8.8X\n"), hRet); + lRet = 0; + } + return lRet; + } + + double StrToDouble(LPCTSTR lpstr) + { + ATLASSERT(lpstr != NULL); + if(lpstr == NULL || lpstr[0] == _T('\0')) + return 0; + + USES_CONVERSION; + HRESULT hRet = E_FAIL; + double dblRet = 0; + if (FAILED(hRet = ::VarR8FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &dblRet))) + { + ATLTRACE2(atlTraceUI, 0, _T("VarR8FromStr failed with result of 0x%8.8X\n"), hRet); + dblRet = 0; + } + return dblRet; + } + + bool StrToDecimal(LPCTSTR lpstr, DECIMAL* pDecimal) + { + ATLASSERT(lpstr != NULL); + ATLASSERT(pDecimal != NULL); + if(lpstr == NULL || pDecimal == NULL) + return false; + + USES_CONVERSION; + HRESULT hRet = E_FAIL; + if (FAILED(hRet = ::VarDecFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, pDecimal))) + { + ATLTRACE2(atlTraceUI, 0, _T("VarDecFromStr failed with result of 0x%8.8X\n"), hRet); + pDecimal->Lo64 = 0; + pDecimal->Hi32 = 0; + pDecimal->signscale = 0; + return false; + } + return true; + } + +// Overrideable PFNLVCOMPARE functions + static int CALLBACK LVCompareText(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = lstrcmp(pParam1->pszValue, pParam2->pszValue); + return pInfo->bDescending ? -nRet : nRet; + } + + static int CALLBACK LVCompareTextNoCase(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = lstrcmpi(pParam1->pszValue, pParam2->pszValue); + return pInfo->bDescending ? -nRet : nRet; + } + + static int CALLBACK LVCompareLong(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = 0; + if(pParam1->lValue > pParam2->lValue) + nRet = 1; + else if(pParam1->lValue < pParam2->lValue) + nRet = -1; + return pInfo->bDescending ? -nRet : nRet; + } + + static int CALLBACK LVCompareDouble(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = 0; + if(pParam1->dblValue > pParam2->dblValue) + nRet = 1; + else if(pParam1->dblValue < pParam2->dblValue) + nRet = -1; + return pInfo->bDescending ? -nRet : nRet; + } + + static int CALLBACK LVCompareCustom(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = pInfo->pT->CompareItemsCustom(pParam1, pParam2, pInfo->iSortCol); + return pInfo->bDescending ? -nRet : nRet; + } + +#ifndef _WIN32_WCE + static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = (int)::VarDecCmp(&pParam1->decValue, &pParam2->decValue); + nRet--; + return pInfo->bDescending ? -nRet : nRet; + } +#else + // Compare mantissas, ignore sign and scale + static int CompareMantissas(const DECIMAL& decLeft, const DECIMAL& decRight) + { + if (decLeft.Hi32 < decRight.Hi32) + { + return -1; + } + if (decLeft.Hi32 > decRight.Hi32) + { + return 1; + } + // Here, decLeft.Hi32 == decRight.Hi32 + if (decLeft.Lo64 < decRight.Lo64) + { + return -1; + } + if (decLeft.Lo64 > decRight.Lo64) + { + return 1; + } + return 0; + } + + // return values: VARCMP_LT, VARCMP_EQ, VARCMP_GT, VARCMP_NULL + static HRESULT VarDecCmp(const DECIMAL* pdecLeft, const DECIMAL* pdecRight) + { + static const ULONG powersOfTen[] = + { + 10ul, + 100ul, + 1000ul, + 10000ul, + 100000ul, + 1000000ul, + 10000000ul, + 100000000ul, + 1000000000ul + }; + static const int largestPower = sizeof(powersOfTen) / sizeof(powersOfTen[0]); + if (!pdecLeft || !pdecRight) + { + return VARCMP_NULL; + } + + // Degenerate case - at least one comparand is of the form + // [+-]0*10^N (denormalized zero) + bool bLeftZero = (!pdecLeft->Lo64 && !pdecLeft->Hi32); + bool bRightZero = (!pdecRight->Lo64 && !pdecRight->Hi32); + if (bLeftZero && bRightZero) + { + return VARCMP_EQ; + } + bool bLeftNeg = ((pdecLeft->sign & DECIMAL_NEG) != 0); + bool bRightNeg = ((pdecRight->sign & DECIMAL_NEG) != 0); + if (bLeftZero) + { + return (bRightNeg ? VARCMP_GT : VARCMP_LT); + } + // This also covers the case where the comparands have different signs + if (bRightZero || bLeftNeg != bRightNeg) + { + return (bLeftNeg ? VARCMP_LT : VARCMP_GT); + } + + // Here both comparands have the same sign and need to be compared + // on mantissa and scale. The result is obvious when + // 1. Scales are equal (then compare mantissas) + // 2. A number with smaller scale is also the one with larger mantissa + // (then this number is obviously larger) + // In the remaining case, we would multiply the number with smaller + // scale by 10 and simultaneously increment its scale (which amounts to + // adding trailing zeros after decimal point), until the numbers fall under + // one of the two cases above + DECIMAL temp; + bool bInvert = bLeftNeg; // the final result needs to be inverted + if (pdecLeft->scale < pdecRight->scale) + { + temp = *pdecLeft; + } + else + { + temp = *pdecRight; + pdecRight = pdecLeft; + bInvert = !bInvert; + } + + // Now temp is the number with smaller (or equal) scale, and + // we can modify it freely without touching original parameters + int comp; + while ((comp = CompareMantissas(temp, *pdecRight)) < 0 && + temp.scale < pdecRight->scale) + { + // Multiply by an appropriate power of 10 + int scaleDiff = pdecRight->scale - temp.scale; + if (scaleDiff > largestPower) + { + // Keep the multiplier representable in 32bit + scaleDiff = largestPower; + } + DWORDLONG power = powersOfTen[scaleDiff - 1]; + // Multiply temp's mantissa by power + DWORDLONG product = temp.Lo32 * power; + ULONG carry = static_cast(product >> 32); + temp.Lo32 = static_cast(product); + product = temp.Mid32 * power + carry; + carry = static_cast(product >> 32); + temp.Mid32 = static_cast(product); + product = temp.Hi32 * power + carry; + if (static_cast(product >> 32)) + { + // Multiplication overflowed - pdecLeft is clearly larger + break; + } + temp.Hi32 = static_cast(product); + temp.scale = (BYTE)(temp.scale + scaleDiff); + } + if (temp.scale < pdecRight->scale) + { + comp = 1; + } + if (bInvert) + { + comp = -comp; + } + return (comp > 0 ? VARCMP_GT : comp < 0 ? VARCMP_LT : VARCMP_EQ); + } + + static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) + { + ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); + + LVCompareParam* pParam1 = (LVCompareParam*)lParam1; + LVCompareParam* pParam2 = (LVCompareParam*)lParam2; + LVSortInfo* pInfo = (LVSortInfo*)lParamSort; + + int nRet = (int)VarDecCmp(&pParam1->decValue, &pParam2->decValue); + nRet--; + return pInfo->bDescending ? -nRet : nRet; + } +#endif // !_WIN32_WCE + + BEGIN_MSG_MAP(CSortListViewImpl) + MESSAGE_HANDLER(LVM_INSERTCOLUMN, OnInsertColumn) + MESSAGE_HANDLER(LVM_DELETECOLUMN, OnDeleteColumn) + NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, OnHeaderItemClick) + NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, OnHeaderItemClick) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + END_MSG_MAP() + + LRESULT OnInsertColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); + if(lRet == -1) + return -1; + + WORD wType = 0; + m_arrColSortType.Add(wType); + int nCount = m_arrColSortType.GetSize(); + ATLASSERT(nCount == GetColumnCount()); + + for(int i = nCount - 1; i > lRet; i--) + m_arrColSortType[i] = m_arrColSortType[i - 1]; + m_arrColSortType[(int)lRet] = LVCOLSORT_TEXT; + + if(lRet <= m_iSortColumn) + m_iSortColumn++; + + return lRet; + } + + LRESULT OnDeleteColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); + if(lRet == 0) + return 0; + + int iCol = (int)wParam; + if(m_iSortColumn == iCol) + m_iSortColumn = -1; + else if(m_iSortColumn > iCol) + m_iSortColumn--; + m_arrColSortType.RemoveAt(iCol); + + return lRet; + } + + LRESULT OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + LPNMHEADER p = (LPNMHEADER)pnmh; + if(p->iButton == 0) + { + int iOld = m_iSortColumn; + bool bDescending = (m_iSortColumn == p->iItem) ? !m_bSortDescending : false; + if(DoSortItems(p->iItem, bDescending)) + NotifyParentSortChanged(p->iItem, iOld); + } + bHandled = FALSE; + return 0; + } + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifndef _WIN32_WCE + if(wParam == SPI_SETNONCLIENTMETRICS) + GetSystemSettings(); +#else // CE specific + wParam; // avoid level 4 warning + GetSystemSettings(); +#endif // _WIN32_WCE + bHandled = FALSE; + return 0; + } + + void GetSystemSettings() + { + if(!m_bCommCtrl6 && !m_bmSort[m_iSortUp].IsNull()) + { + T* pT = static_cast(this); + pT->CreateSortBitmaps(); + if(m_iSortColumn != -1) + SetSortColumn(m_iSortColumn); + } + } + +}; + + +typedef ATL::CWinTraits CSortListViewCtrlTraits; + +template +class ATL_NO_VTABLE CSortListViewCtrlImpl: public ATL::CWindowImpl, public CSortListViewImpl +{ +public: + DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) + + bool SortItems(int iCol, bool bDescending = false) + { + return DoSortItems(iCol, bDescending); + } + + BEGIN_MSG_MAP(CSortListViewCtrlImpl) + MESSAGE_HANDLER(LVM_INSERTCOLUMN, CSortListViewImpl::OnInsertColumn) + MESSAGE_HANDLER(LVM_DELETECOLUMN, CSortListViewImpl::OnDeleteColumn) + NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, CSortListViewImpl::OnHeaderItemClick) + NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, CSortListViewImpl::OnHeaderItemClick) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CSortListViewImpl::OnSettingChange) + END_MSG_MAP() +}; + +class CSortListViewCtrl : public CSortListViewCtrlImpl +{ +public: + DECLARE_WND_SUPERCLASS(_T("WTL_SortListViewCtrl"), GetWndClassName()) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CTabView - implements tab view window + +// TabView Notifications +#define TBVN_PAGEACTIVATED (0U-741) +#define TBVN_CONTEXTMENU (0U-742) + +// Notification data for TBVN_CONTEXTMENU +struct TBVCONTEXTMENUINFO +{ + NMHDR hdr; + POINT pt; +}; + +typedef TBVCONTEXTMENUINFO* LPTBVCONTEXTMENUINFO; + + +template +class ATL_NO_VTABLE CTabViewImpl : public ATL::CWindowImpl +{ +public: + DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE) + +// Declarations and enums + struct TABVIEWPAGE + { + HWND hWnd; + LPTSTR lpstrTitle; + LPVOID pData; + }; + + struct TCITEMEXTRA + { + TCITEMHEADER tciheader; + TABVIEWPAGE tvpage; + + operator LPTCITEM() { return (LPTCITEM)this; } + }; + + enum + { + m_nTabID = 1313, + m_cxMoveMark = 6, + m_cyMoveMark = 3, + m_nMenuItemsMax = (ID_WINDOW_TABLAST - ID_WINDOW_TABFIRST + 1) + }; + +// Data members + ATL::CContainedWindowT m_tab; + int m_cyTabHeight; + + int m_nActivePage; + + int m_nInsertItem; + POINT m_ptStartDrag; + + CMenuHandle m_menu; + + int m_cchTabTextLength; + + int m_nMenuItemsCount; + + ATL::CWindow m_wndTitleBar; + LPTSTR m_lpstrTitleBarBase; + int m_cchTitleBarLength; + + CImageList m_ilDrag; + + bool m_bDestroyPageOnRemove:1; + bool m_bDestroyImageList:1; + bool m_bActivePageMenuItem:1; + bool m_bActiveAsDefaultMenuItem:1; + bool m_bEmptyMenuItem:1; + bool m_bWindowsMenuItem:1; + // internal + bool m_bTabCapture:1; + bool m_bTabDrag:1; + +// Constructor/destructor + CTabViewImpl() : + m_nActivePage(-1), + m_cyTabHeight(0), + m_tab(this, 1), + m_nInsertItem(-1), + m_cchTabTextLength(30), + m_nMenuItemsCount(10), + m_lpstrTitleBarBase(NULL), + m_cchTitleBarLength(100), + m_bDestroyPageOnRemove(true), + m_bDestroyImageList(true), + m_bActivePageMenuItem(true), + m_bActiveAsDefaultMenuItem(false), + m_bEmptyMenuItem(false), + m_bWindowsMenuItem(false), + m_bTabCapture(false), + m_bTabDrag(false) + { + m_ptStartDrag.x = 0; + m_ptStartDrag.y = 0; + } + + ~CTabViewImpl() + { + delete [] m_lpstrTitleBarBase; + } + +// Message filter function - to be called from PreTranslateMessage of the main window + BOOL PreTranslateMessage(MSG* pMsg) + { + if(IsWindow() == FALSE) + return FALSE; + + BOOL bRet = FALSE; + + // Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+Tab - next/previous page) + int nCount = GetPageCount(); + if(nCount > 0) + { + bool bControl = (::GetKeyState(VK_CONTROL) < 0); + if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_TAB) && bControl) + { + if(nCount > 1) + { + int nPage = m_nActivePage; + bool bShift = (::GetKeyState(VK_SHIFT) < 0); + if(bShift) + nPage = (nPage > 0) ? (nPage - 1) : (nCount - 1); + else + nPage = ((nPage >= 0) && (nPage < (nCount - 1))) ? (nPage + 1) : 0; + + SetActivePage(nPage); + T* pT = static_cast(this); + pT->OnPageActivated(m_nActivePage); + } + + bRet = TRUE; + } + } + + // If we are doing drag-drop, check for Escape key that cancels it + if(bRet == FALSE) + { + if(m_bTabCapture && pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) + { + ::ReleaseCapture(); + bRet = TRUE; + } + } + + // Pass the message to the active page + if(bRet == FALSE) + { + if(m_nActivePage != -1) + bRet = (BOOL)::SendMessage(GetPageHWND(m_nActivePage), WM_FORWARDMSG, 0, (LPARAM)pMsg); + } + + return bRet; + } + +// Attributes + int GetPageCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return m_tab.GetItemCount(); + } + + int GetActivePage() const + { + return m_nActivePage; + } + + void SetActivePage(int nPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + T* pT = static_cast(this); + + SetRedraw(FALSE); + + if(m_nActivePage != -1) + ::ShowWindow(GetPageHWND(m_nActivePage), FALSE); + m_nActivePage = nPage; + m_tab.SetCurSel(m_nActivePage); + ::ShowWindow(GetPageHWND(m_nActivePage), TRUE); + + pT->UpdateLayout(); + + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + + if(::GetFocus() != m_tab.m_hWnd) + ::SetFocus(GetPageHWND(m_nActivePage)); + + pT->UpdateTitleBar(); + pT->UpdateMenu(); + } + + HIMAGELIST GetImageList() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return m_tab.GetImageList(); + } + + HIMAGELIST SetImageList(HIMAGELIST hImageList) + { + ATLASSERT(::IsWindow(m_hWnd)); + return m_tab.SetImageList(hImageList); + } + + void SetWindowMenu(HMENU hMenu) + { + ATLASSERT(::IsWindow(m_hWnd)); + + m_menu = hMenu; + + T* pT = static_cast(this); + pT->UpdateMenu(); + } + + void SetTitleBarWindow(HWND hWnd) + { + ATLASSERT(::IsWindow(m_hWnd)); + + delete [] m_lpstrTitleBarBase; + m_lpstrTitleBarBase = NULL; + + m_wndTitleBar = hWnd; + if(hWnd == NULL) + return; + + int cchLen = m_wndTitleBar.GetWindowTextLength() + 1; + ATLTRY(m_lpstrTitleBarBase = new TCHAR[cchLen]); + if(m_lpstrTitleBarBase != NULL) + { + m_wndTitleBar.GetWindowText(m_lpstrTitleBarBase, cchLen); + T* pT = static_cast(this); + pT->UpdateTitleBar(); + } + } + +// Page attributes + HWND GetPageHWND(int nPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + m_tab.GetItem(nPage, tcix); + + return tcix.tvpage.hWnd; + } + + LPCTSTR GetPageTitle(int nPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + if(m_tab.GetItem(nPage, tcix) == FALSE) + return NULL; + + return tcix.tvpage.lpstrTitle; + } + + bool SetPageTitle(int nPage, LPCTSTR lpstrTitle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + T* pT = static_cast(this); + + int cchBuff = lstrlen(lpstrTitle) + 1; + LPTSTR lpstrBuff = NULL; + ATLTRY(lpstrBuff = new TCHAR[cchBuff]); + if(lpstrBuff == NULL) + return false; + + SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle); + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + if(m_tab.GetItem(nPage, tcix) == FALSE) + return false; + + CTempBuffer buff; + LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); + if(lpstrTabText == NULL) + return false; + + delete [] tcix.tvpage.lpstrTitle; + + pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1); + + tcix.tciheader.mask = TCIF_TEXT | TCIF_PARAM; + tcix.tciheader.pszText = lpstrTabText; + tcix.tvpage.lpstrTitle = lpstrBuff; + if(m_tab.SetItem(nPage, tcix) == FALSE) + return false; + + pT->UpdateTitleBar(); + pT->UpdateMenu(); + + return true; + } + + LPVOID GetPageData(int nPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + m_tab.GetItem(nPage, tcix); + + return tcix.tvpage.pData; + } + + LPVOID SetPageData(int nPage, LPVOID pData) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_PARAM; + m_tab.GetItem(nPage, tcix); + LPVOID pDataOld = tcix.tvpage.pData; + + tcix.tvpage.pData = pData; + m_tab.SetItem(nPage, tcix); + + return pDataOld; + } + + int GetPageImage(int nPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_IMAGE; + m_tab.GetItem(nPage, tcix); + + return tcix.tciheader.iImage; + } + + int SetPageImage(int nPage, int nImage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_IMAGE; + m_tab.GetItem(nPage, tcix); + int nImageOld = tcix.tciheader.iImage; + + tcix.tciheader.iImage = nImage; + m_tab.SetItem(nPage, tcix); + + return nImageOld; + } + +// Operations + bool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL) + { + return InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData); + } + + bool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(nPage == GetPageCount() || IsValidPageIndex(nPage)); + + T* pT = static_cast(this); + + int cchBuff = lstrlen(lpstrTitle) + 1; + LPTSTR lpstrBuff = NULL; + ATLTRY(lpstrBuff = new TCHAR[cchBuff]); + if(lpstrBuff == NULL) + return false; + + SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle); + + CTempBuffer buff; + LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); + if(lpstrTabText == NULL) + return false; + + pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1); + + SetRedraw(FALSE); + + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; + tcix.tciheader.pszText = lpstrTabText; + tcix.tciheader.iImage = nImage; + tcix.tvpage.hWnd = hWndView; + tcix.tvpage.lpstrTitle = lpstrBuff; + tcix.tvpage.pData = pData; + int nItem = m_tab.InsertItem(nPage, tcix); + if(nItem == -1) + { + delete [] lpstrBuff; + SetRedraw(TRUE); + return false; + } + + SetActivePage(nItem); + pT->OnPageActivated(m_nActivePage); + + if(GetPageCount() == 1) + pT->ShowTabControl(true); + + pT->UpdateLayout(); + + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + + return true; + } + + void RemovePage(int nPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(IsValidPageIndex(nPage)); + + T* pT = static_cast(this); + + SetRedraw(FALSE); + + if(GetPageCount() == 1) + pT->ShowTabControl(false); + + if(m_bDestroyPageOnRemove) + ::DestroyWindow(GetPageHWND(nPage)); + else + ::ShowWindow(GetPageHWND(nPage), FALSE); + LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(nPage); + delete [] lpstrTitle; + + ATLVERIFY(m_tab.DeleteItem(nPage) != FALSE); + + if(m_nActivePage == nPage) + { + m_nActivePage = -1; + + if(nPage > 0) + { + SetActivePage(nPage - 1); + } + else if(GetPageCount() > 0) + { + SetActivePage(nPage); + } + else + { + SetRedraw(TRUE); + Invalidate(); + UpdateWindow(); + pT->UpdateTitleBar(); + pT->UpdateMenu(); + } + } + else + { + nPage = (nPage < m_nActivePage) ? (m_nActivePage - 1) : m_nActivePage; + m_nActivePage = -1; + SetActivePage(nPage); + } + + pT->OnPageActivated(m_nActivePage); + } + + void RemoveAllPages() + { + ATLASSERT(::IsWindow(m_hWnd)); + + if(GetPageCount() == 0) + return; + + T* pT = static_cast(this); + + SetRedraw(FALSE); + + pT->ShowTabControl(false); + + for(int i = 0; i < GetPageCount(); i++) + { + if(m_bDestroyPageOnRemove) + ::DestroyWindow(GetPageHWND(i)); + else + ::ShowWindow(GetPageHWND(i), FALSE); + LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(i); + delete [] lpstrTitle; + } + m_tab.DeleteAllItems(); + + m_nActivePage = -1; + pT->OnPageActivated(m_nActivePage); + + SetRedraw(TRUE); + Invalidate(); + UpdateWindow(); + + pT->UpdateTitleBar(); + pT->UpdateMenu(); + } + + int PageIndexFromHwnd(HWND hWnd) const + { + int nIndex = -1; + + for(int i = 0; i < GetPageCount(); i++) + { + if(GetPageHWND(i) == hWnd) + { + nIndex = i; + break; + } + } + + return nIndex; + } + + void BuildWindowMenu(HMENU hMenu, int nMenuItemsCount = 10, bool bEmptyMenuItem = true, bool bWindowsMenuItem = true, bool bActivePageMenuItem = true, bool bActiveAsDefaultMenuItem = false) + { + ATLASSERT(::IsWindow(m_hWnd)); + + CMenuHandle menu = hMenu; + T* pT = static_cast(this); + pT; // avoid level 4 warning + int nFirstPos = 0; + + // Find first menu item in our range +#ifndef _WIN32_WCE + for(nFirstPos = 0; nFirstPos < menu.GetMenuItemCount(); nFirstPos++) + { + UINT nID = menu.GetMenuItemID(nFirstPos); + if((nID >= ID_WINDOW_TABFIRST && nID <= ID_WINDOW_TABLAST) || nID == ID_WINDOW_SHOWTABLIST) + break; + } +#else // CE specific + for(nFirstPos = 0; ; nFirstPos++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_ID; + BOOL bRet = menu.GetMenuItemInfo(nFirstPos, TRUE, &mii); + if(bRet == FALSE) + break; + if((mii.wID >= ID_WINDOW_TABFIRST && mii.wID <= ID_WINDOW_TABLAST) || mii.wID == ID_WINDOW_SHOWTABLIST) + break; + } +#endif // _WIN32_WCE + + // Remove all menu items for tab pages + BOOL bRet = TRUE; + while(bRet != FALSE) + bRet = menu.DeleteMenu(nFirstPos, MF_BYPOSITION); + + // Add separator if it's not already there + int nPageCount = GetPageCount(); + if((bWindowsMenuItem || (nPageCount > 0)) && (nFirstPos > 0)) + { + CMenuItemInfo mii; + mii.fMask = MIIM_TYPE; + menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii); + if((nFirstPos <= 0) || ((mii.fType & MFT_SEPARATOR) == 0)) + { + menu.AppendMenu(MF_SEPARATOR); + nFirstPos++; + } + } + + // Add menu items for all pages + if(nPageCount > 0) + { + // Append menu items for all pages + const int cchPrefix = 3; // 2 digits + space + nMenuItemsCount = min(min(nPageCount, nMenuItemsCount), (int)m_nMenuItemsMax); + ATLASSERT(nMenuItemsCount < 100); // 2 digits only + if(nMenuItemsCount >= 100) + nMenuItemsCount = 99; + + for(int i = 0; i < nMenuItemsCount; i++) + { + LPCTSTR lpstrTitle = GetPageTitle(i); + int nLen = lstrlen(lpstrTitle); + CTempBuffer buff; + LPTSTR lpstrText = buff.Allocate(cchPrefix + nLen + 1); + ATLASSERT(lpstrText != NULL); + if(lpstrText != NULL) + { + LPCTSTR lpstrFormat = (i < 9) ? _T("&%i %s") : _T("%i %s"); + SecureHelper::wsprintf_x(lpstrText, cchPrefix + nLen + 1, lpstrFormat, i + 1, lpstrTitle); + menu.AppendMenu(MF_STRING, ID_WINDOW_TABFIRST + i, lpstrText); + } + } + + // Mark active page + if(bActivePageMenuItem && (m_nActivePage != -1)) + { +#ifndef _WIN32_WCE + if(bActiveAsDefaultMenuItem) + { + menu.SetMenuDefaultItem((UINT)-1, TRUE); + menu.SetMenuDefaultItem(nFirstPos + m_nActivePage, TRUE); + } + else +#else // CE specific + bActiveAsDefaultMenuItem; // avoid level 4 warning +#endif // _WIN32_WCE + { + menu.CheckMenuRadioItem(nFirstPos, nFirstPos + nMenuItemsCount, nFirstPos + m_nActivePage, MF_BYPOSITION); + } + } + } + else + { + if(bEmptyMenuItem) + { + menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_TABFIRST, pT->GetEmptyListText()); + menu.EnableMenuItem(ID_WINDOW_TABFIRST, MF_GRAYED); + } + + // Remove separator if nothing else is there + if(!bEmptyMenuItem && !bWindowsMenuItem && (nFirstPos > 0)) + { + CMenuItemInfo mii; + mii.fMask = MIIM_TYPE; + menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii); + if((mii.fType & MFT_SEPARATOR) != 0) + menu.DeleteMenu(nFirstPos - 1, MF_BYPOSITION); + } + } + + // Add "Windows..." menu item + if(bWindowsMenuItem) + menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_SHOWTABLIST, pT->GetWindowsMenuItemText()); + } + +// Message map and handlers + BEGIN_MSG_MAP(CTabViewImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + NOTIFY_HANDLER(m_nTabID, TCN_SELCHANGE, OnTabChanged) + NOTIFY_ID_HANDLER(m_nTabID, OnTabNotification) +#ifndef _WIN32_WCE + NOTIFY_CODE_HANDLER(TTN_GETDISPINFO, OnTabGetDispInfo) +#endif // !_WIN32_WCE + FORWARD_NOTIFICATIONS() + ALT_MSG_MAP(1) // tab control + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnTabLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONUP, OnTabLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnTabCaptureChanged) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnTabMouseMove) + MESSAGE_HANDLER(WM_RBUTTONUP, OnTabRButtonUp) + MESSAGE_HANDLER(WM_SYSKEYDOWN, OnTabSysKeyDown) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->CreateTabControl(); + + return 0; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + RemoveAllPages(); + + if(m_bDestroyImageList) + { + CImageList il = m_tab.SetImageList(NULL); + if(il.m_hImageList != NULL) + il.Destroy(); + } + + return 0; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + return 0; + } + + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_nActivePage != -1) + ::SetFocus(GetPageHWND(m_nActivePage)); + return 0; + } + + LRESULT OnTabChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + SetActivePage(m_tab.GetCurSel()); + T* pT = static_cast(this); + pT->OnPageActivated(m_nActivePage); + + return 0; + } + + LRESULT OnTabNotification(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + // nothing to do - this just blocks all tab control + // notifications from being propagated further + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + LPNMTTDISPINFO pTTDI = (LPNMTTDISPINFO)pnmh; + if(pTTDI->hdr.hwndFrom == m_tab.GetTooltips()) + { + T* pT = static_cast(this); + pT->UpdateTooltipText(pTTDI); + } + else + { + bHandled = FALSE; + } + + return 0; + } +#endif // !_WIN32_WCE + +// Tab control message handlers + LRESULT OnTabLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(m_tab.GetItemCount() > 1) + { + m_bTabCapture = true; + m_tab.SetCapture(); + + m_ptStartDrag.x = GET_X_LPARAM(lParam); + m_ptStartDrag.y = GET_Y_LPARAM(lParam); + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnTabLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(m_bTabCapture) + { + if(m_bTabDrag) + { + TCHITTESTINFO hti = { 0 }; + hti.pt.x = GET_X_LPARAM(lParam); + hti.pt.y = GET_Y_LPARAM(lParam); + int nItem = m_tab.HitTest(&hti); + if(nItem != -1) + MovePage(m_nActivePage, nItem); + } + + ::ReleaseCapture(); + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnTabCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bTabCapture) + { + m_bTabCapture = false; + + if(m_bTabDrag) + { + m_bTabDrag = false; + T* pT = static_cast(this); + pT->DrawMoveMark(-1); + +#ifndef _WIN32_WCE + m_ilDrag.DragLeave(GetDesktopWindow()); +#endif // !_WIN32_WCE + m_ilDrag.EndDrag(); + + m_ilDrag.Destroy(); + m_ilDrag.m_hImageList = NULL; + } + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnTabMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + bHandled = FALSE; + + if(m_bTabCapture) + { + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + + if(!m_bTabDrag) + { +#ifndef _WIN32_WCE + if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CXDRAG) || + abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CYDRAG)) +#else // CE specific + if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= 4 || + abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= 4) +#endif // _WIN32_WCE + { + T* pT = static_cast(this); + pT->GenerateDragImage(m_nActivePage); + + int cxCursor = ::GetSystemMetrics(SM_CXCURSOR); + int cyCursor = ::GetSystemMetrics(SM_CYCURSOR); + m_ilDrag.BeginDrag(0, -(cxCursor / 2), -(cyCursor / 2)); +#ifndef _WIN32_WCE + POINT ptEnter = m_ptStartDrag; + m_tab.ClientToScreen(&ptEnter); + m_ilDrag.DragEnter(GetDesktopWindow(), ptEnter); +#endif // !_WIN32_WCE + + m_bTabDrag = true; + } + } + + if(m_bTabDrag) + { + TCHITTESTINFO hti = { 0 }; + hti.pt = pt; + int nItem = m_tab.HitTest(&hti); + + T* pT = static_cast(this); + pT->SetMoveCursor(nItem != -1); + + if(m_nInsertItem != nItem) + pT->DrawMoveMark(nItem); + + m_ilDrag.DragShowNolock((nItem != -1) ? TRUE : FALSE); + m_tab.ClientToScreen(&pt); + m_ilDrag.DragMove(pt); + + bHandled = TRUE; + } + } + + return 0; + } + + LRESULT OnTabRButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + TCHITTESTINFO hti = { 0 }; + hti.pt.x = GET_X_LPARAM(lParam); + hti.pt.y = GET_Y_LPARAM(lParam); + int nItem = m_tab.HitTest(&hti); + if(nItem != -1) + { + T* pT = static_cast(this); + pT->OnContextMenu(nItem, hti.pt); + } + + return 0; + } + + LRESULT OnTabSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bool bShift = (::GetKeyState(VK_SHIFT) < 0); + if(wParam == VK_F10 && bShift) + { + if(m_nActivePage != -1) + { + RECT rect = { 0 }; + m_tab.GetItemRect(m_nActivePage, &rect); + POINT pt = { rect.left, rect.bottom }; + T* pT = static_cast(this); + pT->OnContextMenu(m_nActivePage, pt); + } + } + else + { + bHandled = FALSE; + } + + return 0; + } + +// Implementation helpers + bool IsValidPageIndex(int nPage) const + { + return (nPage >= 0 && nPage < GetPageCount()); + } + + bool MovePage(int nMovePage, int nInsertBeforePage) + { + ATLASSERT(IsValidPageIndex(nMovePage)); + ATLASSERT(IsValidPageIndex(nInsertBeforePage)); + + if(!IsValidPageIndex(nMovePage) || !IsValidPageIndex(nInsertBeforePage)) + return false; + + if(nMovePage == nInsertBeforePage) + return true; // nothing to do + + CTempBuffer buff; + LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); + if(lpstrTabText == NULL) + return false; + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; + tcix.tciheader.pszText = lpstrTabText; + tcix.tciheader.cchTextMax = m_cchTabTextLength + 1; + BOOL bRet = m_tab.GetItem(nMovePage, tcix); + ATLASSERT(bRet != FALSE); + if(bRet == FALSE) + return false; + + int nInsertItem = (nInsertBeforePage > nMovePage) ? nInsertBeforePage + 1 : nInsertBeforePage; + int nNewItem = m_tab.InsertItem(nInsertItem, tcix); + ATLASSERT(nNewItem == nInsertItem); + if(nNewItem != nInsertItem) + { + ATLVERIFY(m_tab.DeleteItem(nNewItem)); + return false; + } + + if(nMovePage > nInsertBeforePage) + ATLVERIFY(m_tab.DeleteItem(nMovePage + 1) != FALSE); + else if(nMovePage < nInsertBeforePage) + ATLVERIFY(m_tab.DeleteItem(nMovePage) != FALSE); + + SetActivePage(nInsertBeforePage); + T* pT = static_cast(this); + pT->OnPageActivated(m_nActivePage); + + return true; + } + +// Implementation overrideables + bool CreateTabControl() + { +#ifndef _WIN32_WCE + m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID); +#else // CE specific + m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, m_nTabID); +#endif // _WIN32_WCE + ATLASSERT(m_tab.m_hWnd != NULL); + if(m_tab.m_hWnd == NULL) + return false; + + m_tab.SetFont(AtlGetDefaultGuiFont()); + + m_tab.SetItemExtra(sizeof(TABVIEWPAGE)); + + T* pT = static_cast(this); + m_cyTabHeight = pT->CalcTabHeight(); + + return true; + } + + int CalcTabHeight() + { + int nCount = m_tab.GetItemCount(); + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_TEXT; + tcix.tciheader.pszText = _T("NS"); + int nIndex = m_tab.InsertItem(nCount, tcix); + + RECT rect = { 0, 0, 1000, 1000 }; + m_tab.AdjustRect(FALSE, &rect); + + RECT rcWnd = { 0, 0, 1000, rect.top }; + ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle()); + + int nHeight = rcWnd.bottom - rcWnd.top; + + m_tab.DeleteItem(nIndex); + + return nHeight; + } + + void ShowTabControl(bool bShow) + { + m_tab.ShowWindow(bShow ? SW_SHOWNOACTIVATE : SW_HIDE); + } + + void UpdateLayout() + { + RECT rect; + GetClientRect(&rect); + + if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0)) + m_tab.SetWindowPos(NULL, 0, 0, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER); + + if(m_nActivePage != -1) + ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, m_cyTabHeight, rect.right - rect.left, rect.bottom - rect.top - m_cyTabHeight, SWP_NOZORDER); + } + + void UpdateMenu() + { + if(m_menu.m_hMenu != NULL) + BuildWindowMenu(m_menu, m_nMenuItemsCount, m_bEmptyMenuItem, m_bWindowsMenuItem, m_bActivePageMenuItem, m_bActiveAsDefaultMenuItem); + } + + void UpdateTitleBar() + { + if(!m_wndTitleBar.IsWindow() || m_lpstrTitleBarBase == NULL) + return; // nothing to do + + if(m_nActivePage != -1) + { + T* pT = static_cast(this); + LPCTSTR lpstrTitle = pT->GetPageTitle(m_nActivePage); + LPCTSTR lpstrDivider = pT->GetTitleDividerText(); + int cchBuffer = m_cchTitleBarLength + lstrlen(lpstrDivider) + lstrlen(m_lpstrTitleBarBase) + 1; + CTempBuffer buff; + LPTSTR lpstrPageTitle = buff.Allocate(cchBuffer); + ATLASSERT(lpstrPageTitle != NULL); + if(lpstrPageTitle != NULL) + { + pT->ShortenTitle(lpstrTitle, lpstrPageTitle, m_cchTitleBarLength + 1); + SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, lpstrDivider); + SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, m_lpstrTitleBarBase); + } + else + { + lpstrPageTitle = m_lpstrTitleBarBase; + } + + m_wndTitleBar.SetWindowText(lpstrPageTitle); + } + else + { + m_wndTitleBar.SetWindowText(m_lpstrTitleBarBase); + } + } + + void DrawMoveMark(int nItem) + { + T* pT = static_cast(this); + + if(m_nInsertItem != -1) + { + RECT rect = { 0 }; + pT->GetMoveMarkRect(rect); + m_tab.InvalidateRect(&rect); + } + + m_nInsertItem = nItem; + + if(m_nInsertItem != -1) + { + CClientDC dc(m_tab.m_hWnd); + + RECT rect = { 0 }; + pT->GetMoveMarkRect(rect); + + CPen pen; + pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT)); + CBrush brush; + brush.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT)); + + HPEN hPenOld = dc.SelectPen(pen); + HBRUSH hBrushOld = dc.SelectBrush(brush); + + int x = rect.left; + int y = rect.top; + POINT ptsTop[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y + m_cyMoveMark } }; + dc.Polygon(ptsTop, 3); + + y = rect.bottom - 1; + POINT ptsBottom[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y - m_cyMoveMark } }; + dc.Polygon(ptsBottom, 3); + + dc.SelectPen(hPenOld); + dc.SelectBrush(hBrushOld); + } + } + + void GetMoveMarkRect(RECT& rect) const + { + m_tab.GetClientRect(&rect); + + RECT rcItem = { 0 }; + m_tab.GetItemRect(m_nInsertItem, &rcItem); + + if(m_nInsertItem <= m_nActivePage) + { + rect.left = rcItem.left - m_cxMoveMark / 2 - 1; + rect.right = rcItem.left + m_cxMoveMark / 2; + } + else + { + rect.left = rcItem.right - m_cxMoveMark / 2 - 1; + rect.right = rcItem.right + m_cxMoveMark / 2; + } + } + + void SetMoveCursor(bool bCanMove) + { + ::SetCursor(::LoadCursor(NULL, bCanMove ? IDC_ARROW : IDC_NO)); + } + + void GenerateDragImage(int nItem) + { + ATLASSERT(IsValidPageIndex(nItem)); + +#ifndef _WIN32_WCE + RECT rcItem = { 0 }; + m_tab.GetItemRect(nItem, &rcItem); + ::InflateRect(&rcItem, 2, 2); // make bigger to cover selected item +#else // CE specific + nItem; // avoid level 4 warning + RECT rcItem = { 0, 0, 40, 20 }; +#endif // _WIN32_WCE + + ATLASSERT(m_ilDrag.m_hImageList == NULL); + m_ilDrag.Create(rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, ILC_COLORDDB | ILC_MASK, 1, 1); + + CClientDC dc(m_hWnd); + CDC dcMem; + dcMem.CreateCompatibleDC(dc); + ATLASSERT(dcMem.m_hDC != NULL); + dcMem.SetViewportOrg(-rcItem.left, -rcItem.top); + + CBitmap bmp; + bmp.CreateCompatibleBitmap(dc, rcItem.right - rcItem.left, rcItem.bottom - rcItem.top); + ATLASSERT(bmp.m_hBitmap != NULL); + + HBITMAP hBmpOld = dcMem.SelectBitmap(bmp); +#ifndef _WIN32_WCE + m_tab.SendMessage(WM_PRINTCLIENT, (WPARAM)dcMem.m_hDC); +#else // CE specific + dcMem.Rectangle(&rcItem); +#endif // _WIN32_WCE + dcMem.SelectBitmap(hBmpOld); + + ATLVERIFY(m_ilDrag.Add(bmp.m_hBitmap, RGB(255, 0, 255)) != -1); + } + + void ShortenTitle(LPCTSTR lpstrTitle, LPTSTR lpstrShortTitle, int cchShortTitle) + { + if(lstrlen(lpstrTitle) >= cchShortTitle) + { + LPCTSTR lpstrEllipsis = _T("..."); + int cchEllipsis = lstrlen(lpstrEllipsis); + SecureHelper::strncpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle, cchShortTitle - cchEllipsis - 1); + SecureHelper::strcat_x(lpstrShortTitle, cchShortTitle, lpstrEllipsis); + } + else + { + SecureHelper::strcpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle); + } + } + +#ifndef _WIN32_WCE + void UpdateTooltipText(LPNMTTDISPINFO pTTDI) + { + ATLASSERT(pTTDI != NULL); + pTTDI->lpszText = (LPTSTR)GetPageTitle((int)pTTDI->hdr.idFrom); + } +#endif // !_WIN32_WCE + +// Text for menu items and title bar - override to provide different strings + static LPCTSTR GetEmptyListText() + { + return _T("(Empty)"); + } + + static LPCTSTR GetWindowsMenuItemText() + { + return _T("&Windows..."); + } + + static LPCTSTR GetTitleDividerText() + { + return _T(" - "); + } + +// Notifications - override to provide different behavior + void OnPageActivated(int nPage) + { + NMHDR nmhdr = { 0 }; + nmhdr.hwndFrom = m_hWnd; + nmhdr.idFrom = nPage; + nmhdr.code = TBVN_PAGEACTIVATED; + ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr); + } + + void OnContextMenu(int nPage, POINT pt) + { + m_tab.ClientToScreen(&pt); + + TBVCONTEXTMENUINFO cmi = { 0 }; + cmi.hdr.hwndFrom = m_hWnd; + cmi.hdr.idFrom = nPage; + cmi.hdr.code = TBVN_CONTEXTMENU; + cmi.pt = pt; + ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&cmi); + } +}; + + +class CTabView : public CTabViewImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_TabView"), 0, COLOR_APPWORKSPACE) +}; + +}; // namespace WTL + +#endif // __ATLCTRLX_H__ diff --git a/wtl/wtl/include/atlddx.h b/wtl/wtl/include/atlddx.h new file mode 100644 index 00000000..ad4249a8 --- /dev/null +++ b/wtl/wtl/include/atlddx.h @@ -0,0 +1,624 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLDDX_H__ +#define __ATLDDX_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlddx.h requires atlapp.h to be included first +#endif + +#if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) + #error Cannot use floating point DDX with _ATL_MIN_CRT defined +#endif // defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) + +#ifdef _ATL_USE_DDX_FLOAT + #include +#endif // _ATL_USE_DDX_FLOAT + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CWinDataExchange + + +namespace WTL +{ + +// Constants +#define DDX_LOAD FALSE +#define DDX_SAVE TRUE + +// DDX map macros +#define BEGIN_DDX_MAP(thisClass) \ + BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \ + { \ + bSaveAndValidate; \ + nCtlID; + +#define DDX_TEXT(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \ + return FALSE; \ + } + +#define DDX_TEXT_LEN(nID, var, len) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \ + return FALSE; \ + } + +#define DDX_INT(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \ + return FALSE; \ + } + +#define DDX_INT_RANGE(nID, var, min, max) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \ + return FALSE; \ + } + +#define DDX_UINT(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \ + return FALSE; \ + } + +#define DDX_UINT_RANGE(nID, var, min, max) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \ + return FALSE; \ + } + +#ifdef _ATL_USE_DDX_FLOAT +#define DDX_FLOAT(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Float(nID, var, bSaveAndValidate)) \ + return FALSE; \ + } + +#define DDX_FLOAT_RANGE(nID, var, min, max) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \ + return FALSE; \ + } +#define DDX_FLOAT_P(nID, var, precision) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \ + return FALSE; \ + } + +#define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + { \ + if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \ + return FALSE; \ + } +#endif // _ATL_USE_DDX_FLOAT + +#define DDX_CONTROL(nID, obj) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Control(nID, obj, bSaveAndValidate); + +#define DDX_CONTROL_HANDLE(nID, obj) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Control_Handle(nID, obj, bSaveAndValidate); + +#define DDX_CHECK(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Check(nID, var, bSaveAndValidate); + +#define DDX_RADIO(nID, var) \ + if(nCtlID == (UINT)-1 || nCtlID == nID) \ + DDX_Radio(nID, var, bSaveAndValidate); + +#define END_DDX_MAP() \ + return TRUE; \ + } + + +/////////////////////////////////////////////////////////////////////////////// +// CWinDataExchange - provides support for DDX + +template +class CWinDataExchange +{ +public: +// Data exchange method - override in your derived class + BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1) + { + // this one should never be called, override it in + // your derived class by implementing DDX map + ATLASSERT(FALSE); + return FALSE; + } + +// Helpers for validation error reporting + enum _XDataType + { + ddxDataNull = 0, + ddxDataText = 1, + ddxDataInt = 2, + ddxDataFloat = 3, + ddxDataDouble = 4 + }; + + struct _XTextData + { + int nLength; + int nMaxLength; + }; + + struct _XIntData + { + long nVal; + long nMin; + long nMax; + }; + + struct _XFloatData + { + double nVal; + double nMin; + double nMax; + }; + + struct _XData + { + _XDataType nDataType; + union + { + _XTextData textData; + _XIntData intData; + _XFloatData floatData; + }; + }; + +// Text exchange + BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + HWND hWndCtrl = pT->GetDlgItem(nID); + int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR)); + if(nRetLen < ::GetWindowTextLength(hWndCtrl)) + bSuccess = FALSE; + } + else + { + ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength); + bSuccess = pT->SetDlgItemText(nID, lpstrText); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nLength > 0); + if(lstrlen(lpstrText) > nLength) + { + _XData data = { ddxDataText }; + data.textData.nLength = lstrlen(lpstrText); + data.textData.nMaxLength = nLength; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + + BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + bSuccess = pT->GetDlgItemText(nID, bstrText); + } + else + { + USES_CONVERSION; + LPTSTR lpstrText = OLE2T(bstrText); + ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength); + bSuccess = pT->SetDlgItemText(nID, lpstrText); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nLength > 0); + if((int)::SysStringLen(bstrText) > nLength) + { + _XData data = { ddxDataText }; + data.textData.nLength = (int)::SysStringLen(bstrText); + data.textData.nMaxLength = nLength; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + + BOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText); + } + else + { + USES_CONVERSION; + LPTSTR lpstrText = OLE2T(bstrText); + ATLASSERT(!bValidate || lstrlen(lpstrText) <= nLength); + bSuccess = pT->SetDlgItemText(nID, lpstrText); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nLength > 0); + if((int)bstrText.Length() > nLength) + { + _XData data = { ddxDataText }; + data.textData.nLength = (int)bstrText.Length(); + data.textData.nMaxLength = nLength; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL DDX_Text(UINT nID, _CSTRING_NS::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + HWND hWndCtrl = pT->GetDlgItem(nID); + int nLen = ::GetWindowTextLength(hWndCtrl); + int nRetLen = -1; + LPTSTR lpstr = strText.GetBufferSetLength(nLen); + if(lpstr != NULL) + { + nRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1); + strText.ReleaseBuffer(); + } + if(nRetLen < nLen) + bSuccess = FALSE; + } + else + { + bSuccess = pT->SetDlgItemText(nID, strText); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nLength > 0); + if(strText.GetLength() > nLength) + { + _XData data = { ddxDataText }; + data.textData.nLength = strText.GetLength(); + data.textData.nMaxLength = nLength; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +// Numeric exchange + template + BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + + if(bSave) + { + nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned); + } + else + { + ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); + bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nMin != nMax); + if(nVal < nMin || nVal > nMax) + { + _XData data = { ddxDataInt }; + data.intData.nVal = (long)nVal; + data.intData.nMin = (long)nMin; + data.intData.nMax = (long)nMax; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + +// Float exchange +#ifdef _ATL_USE_DDX_FLOAT + static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d) + { + ATLASSERT(lpszText != NULL); + while (*lpszText == _T(' ') || *lpszText == _T('\t')) + lpszText++; + + TCHAR chFirst = lpszText[0]; + d = _tcstod(lpszText, (LPTSTR*)&lpszText); + if (d == 0.0 && chFirst != _T('0')) + return FALSE; // could not convert + while (*lpszText == _T(' ') || *lpszText == _T('\t')) + lpszText++; + + if (*lpszText != _T('\0')) + return FALSE; // not terminated properly + + return TRUE; + } + + BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + const int cchBuff = 32; + TCHAR szBuff[cchBuff] = { 0 }; + + if(bSave) + { + pT->GetDlgItemText(nID, szBuff, cchBuff); + double d = 0; + if(_AtlSimpleFloatParse(szBuff, d)) + nVal = (float)d; + else + bSuccess = FALSE; + } + else + { + ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); + SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); + bSuccess = pT->SetDlgItemText(nID, szBuff); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nMin != nMax); + if(nVal < nMin || nVal > nMax) + { + _XData data = { ddxDataFloat }; + data.floatData.nVal = (double)nVal; + data.floatData.nMin = (double)nMin; + data.floatData.nMax = (double)nMax; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } + + BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG) + { + T* pT = static_cast(this); + BOOL bSuccess = TRUE; + const int cchBuff = 32; + TCHAR szBuff[cchBuff] = { 0 }; + + if(bSave) + { + pT->GetDlgItemText(nID, szBuff, cchBuff); + double d = 0; + if(_AtlSimpleFloatParse(szBuff, d)) + nVal = d; + else + bSuccess = FALSE; + } + else + { + ATLASSERT(!bValidate || nVal >= nMin && nVal <= nMax); + SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); + bSuccess = pT->SetDlgItemText(nID, szBuff); + } + + if(!bSuccess) + { + pT->OnDataExchangeError(nID, bSave); + } + else if(bSave && bValidate) // validation + { + ATLASSERT(nMin != nMax); + if(nVal < nMin || nVal > nMax) + { + _XData data = { ddxDataFloat }; + data.floatData.nVal = nVal; + data.floatData.nMin = nMin; + data.floatData.nMax = nMax; + pT->OnDataValidateError(nID, bSave, data); + bSuccess = FALSE; + } + } + return bSuccess; + } +#endif // _ATL_USE_DDX_FLOAT + +// Full control subclassing (for CWindowImpl derived controls) + template + void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave) + { + if(!bSave && ctrl.m_hWnd == NULL) + { + T* pT = static_cast(this); + ctrl.SubclassWindow(pT->GetDlgItem(nID)); + } + } + +// Simple control attaching (for HWND wrapper controls) + template + void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave) + { + if(!bSave && ctrl.m_hWnd == NULL) + { + T* pT = static_cast(this); + ctrl = pT->GetDlgItem(nID); + } + } + +// Control state + void DDX_Check(UINT nID, int& nValue, BOOL bSave) + { + T* pT = static_cast(this); + HWND hWndCtrl = pT->GetDlgItem(nID); + if(bSave) + { + nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L); + ATLASSERT(nValue >= 0 && nValue <= 2); + } + else + { + if(nValue < 0 || nValue > 2) + { + ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - dialog data checkbox value (%d) out of range.\n"), nValue); + nValue = 0; // default to off + } + ::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L); + } + } + + // variant that supports bool (checked/not-checked, no intermediate state) + void DDX_Check(UINT nID, bool& bCheck, BOOL bSave) + { + int nValue = bCheck ? 1 : 0; + DDX_Check(nID, nValue, bSave); + + if(bSave) + { + if(nValue == 2) + ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - checkbox state (%d) out of supported range.\n"), nValue); + bCheck = (nValue == 1); + } + } + + void DDX_Radio(UINT nID, int& nValue, BOOL bSave) + { + T* pT = static_cast(this); + HWND hWndCtrl = pT->GetDlgItem(nID); + ATLASSERT(hWndCtrl != NULL); + + // must be first in a group of auto radio buttons + ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP); + ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON); + + if(bSave) + nValue = -1; // value if none found + + // walk all children in group + int nButton = 0; + do + { + if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON) + { + // control in group is a radio button + if(bSave) + { + if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0) + { + ATLASSERT(nValue == -1); // only set once + nValue = nButton; + } + } + else + { + // select button + ::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L); + } + nButton++; + } + else + { + ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - skipping non-radio button in group.\n")); + } + hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT); + } + while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP)); + } + +// Overrideables + void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/) + { + // Override to display an error message + ::MessageBeep((UINT)-1); + T* pT = static_cast(this); + ::SetFocus(pT->GetDlgItem(nCtrlID)); + } + + void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/) + { + // Override to display an error message + ::MessageBeep((UINT)-1); + T* pT = static_cast(this); + ::SetFocus(pT->GetDlgItem(nCtrlID)); + } +}; + +}; // namespace WTL + +#endif // __ATLDDX_H__ diff --git a/wtl/wtl/include/atldlgs.h b/wtl/wtl/include/atldlgs.h new file mode 100644 index 00000000..c0fd5686 --- /dev/null +++ b/wtl/wtl/include/atldlgs.h @@ -0,0 +1,6212 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLDLGS_H__ +#define __ATLDLGS_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atldlgs.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atldlgs.h requires atlwin.h to be included first +#endif + +#include +#include + +#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + #include +#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CFileDialogImpl +// CFileDialog +// CFileDialogEx +// CMultiFileDialogImpl +// CMultiFileDialog +// CShellFileDialogImpl +// CShellFileOpenDialogImpl +// CShellFileOpenDialog +// CShellFileSaveDialogImpl +// CShellFileSaveDialog +// CFolderDialogImpl +// CFolderDialog +// CFontDialogImpl +// CFontDialog +// CRichEditFontDialogImpl +// CRichEditFontDialog +// CColorDialogImpl +// CColorDialog +// CPrintDialogImpl +// CPrintDialog +// CPrintDialogExImpl +// CPrintDialogEx +// CPageSetupDialogImpl +// CPageSetupDialog +// CFindReplaceDialogImpl +// CFindReplaceDialog +// +// CMemDlgTemplate +// CIndirectDialogImpl +// +// CPropertySheetWindow +// CPropertySheetImpl +// CPropertySheet +// CPropertyPageWindow +// CPropertyPageImpl +// CPropertyPage +// CAxPropertyPageImpl +// CAxPropertyPage +// +// CWizard97SheetWindow +// CWizard97SheetImpl +// CWizard97Sheet +// CWizard97PageWindow +// CWizard97PageImpl +// CWizard97ExteriorPageImpl +// CWizard97InteriorPageImpl +// +// CAeroWizardFrameWindow +// CAeroWizardFrameImpl +// CAeroWizardFrame +// CAeroWizardPageWindow +// CAeroWizardPageImpl +// CAeroWizardPage +// CAeroWizardAxPageImpl +// CAeroWizardAxPage +// +// CTaskDialogConfig +// CTaskDialogImpl +// CTaskDialog +// +// Global functions: +// AtlTaskDialog() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CFileDialogImpl - used for File Open or File Save As + +// compatibility with the old (vc6.0) headers +#if (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400) + #ifndef CDSIZEOF_STRUCT + #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) + #endif + #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName) + #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName) + #ifdef UNICODE + #define OPENFILENAME_SIZE_VERSION_400 OPENFILENAME_SIZE_VERSION_400W + #else + #define OPENFILENAME_SIZE_VERSION_400 OPENFILENAME_SIZE_VERSION_400A + #endif // !UNICODE +#endif // (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400) + +#if !defined(_WIN32_WCE) && !defined(CDN_INCLUDEITEM) + #define CDN_INCLUDEITEM (CDN_FIRST - 0x0007) +#endif + +template +class ATL_NO_VTABLE CFileDialogImpl : public ATL::CDialogImplBase +{ +public: +#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) + OPENFILENAMEEX m_ofn; +#else + OPENFILENAME m_ofn; +#endif + BOOL m_bOpenFileDialog; // TRUE for file open, FALSE for file save + TCHAR m_szFileTitle[_MAX_FNAME]; // contains file title after return + TCHAR m_szFileName[_MAX_PATH]; // contains full path name after return + + CFileDialogImpl(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + { + memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL + m_szFileName[0] = _T('\0'); + m_szFileTitle[0] = _T('\0'); + + m_bOpenFileDialog = bOpenFileDialog; + + m_ofn.lStructSize = sizeof(m_ofn); +#if (_WIN32_WINNT >= 0x0500) + // adjust struct size if running on older version of Windows + if(AtlIsOldWindows()) + { + ATLASSERT(sizeof(m_ofn) > OPENFILENAME_SIZE_VERSION_400); // must be + m_ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; + } +#endif // (_WIN32_WINNT >= 0x0500) + m_ofn.lpstrFile = m_szFileName; + m_ofn.nMaxFile = _MAX_PATH; + m_ofn.lpstrDefExt = lpszDefExt; + m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle; + m_ofn.nMaxFileTitle = _MAX_FNAME; +#ifndef _WIN32_WCE + m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING; +#else // CE specific + m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK; +#endif // !_WIN32_WCE + m_ofn.lpstrFilter = lpszFilter; + m_ofn.hInstance = ModuleHelper::GetResourceInstance(); + m_ofn.lpfnHook = (LPOFNHOOKPROC)T::StartDialogProc; + m_ofn.hwndOwner = hWndParent; + + // setup initial file name + if(lpszFileName != NULL) + SecureHelper::strncpy_x(m_szFileName, _countof(m_szFileName), lpszFileName, _TRUNCATE); + } + + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_ofn.Flags & OFN_ENABLEHOOK) != 0); + ATLASSERT(m_ofn.lpfnHook != NULL); // can still be a user hook + + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + if(m_ofn.hwndOwner == NULL) // set only if not specified before + m_ofn.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this); + + BOOL bRet; + if(m_bOpenFileDialog) +#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) + bRet = ::GetOpenFileNameEx(&m_ofn); + else + bRet = ::GetSaveFileName((LPOPENFILENAME)&m_ofn); +#else + bRet = ::GetOpenFileName(&m_ofn); + else + bRet = ::GetSaveFileName(&m_ofn); +#endif + + m_hWnd = NULL; + + return bRet ? IDOK : IDCANCEL; + } + +// Attributes + ATL::CWindow GetFileDialogWindow() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return ATL::CWindow(GetParent()); + } + + int GetFilePath(LPTSTR lpstrFilePath, int nLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + return (int)GetFileDialogWindow().SendMessage(CDM_GETFILEPATH, nLength, (LPARAM)lpstrFilePath); + } + + int GetFolderIDList(LPVOID lpBuff, int nLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERIDLIST, nLength, (LPARAM)lpBuff); + } + + int GetFolderPath(LPTSTR lpstrFolderPath, int nLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERPATH, nLength, (LPARAM)lpstrFolderPath); + } + + int GetSpec(LPTSTR lpstrSpec, int nLength) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + return (int)GetFileDialogWindow().SendMessage(CDM_GETSPEC, nLength, (LPARAM)lpstrSpec); + } + + void SetControlText(int nCtrlID, LPCTSTR lpstrText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + GetFileDialogWindow().SendMessage(CDM_SETCONTROLTEXT, nCtrlID, (LPARAM)lpstrText); + } + + void SetDefExt(LPCTSTR lpstrExt) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + GetFileDialogWindow().SendMessage(CDM_SETDEFEXT, 0, (LPARAM)lpstrExt); + } + + BOOL GetReadOnlyPref() const // return TRUE if readonly checked + { + return ((m_ofn.Flags & OFN_READONLY) != 0) ? TRUE : FALSE; + } + +// Operations + void HideControl(int nCtrlID) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); + + GetFileDialogWindow().SendMessage(CDM_HIDECONTROL, nCtrlID); + } + +// Special override for common dialogs + BOOL EndDialog(INT_PTR /*nRetCode*/ = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + GetFileDialogWindow().SendMessage(WM_COMMAND, MAKEWPARAM(IDCANCEL, 0)); + return TRUE; + } + +// Message map and handlers + BEGIN_MSG_MAP(CFileDialogImpl) + NOTIFY_CODE_HANDLER(CDN_FILEOK, _OnFileOK) + NOTIFY_CODE_HANDLER(CDN_FOLDERCHANGE, _OnFolderChange) + NOTIFY_CODE_HANDLER(CDN_HELP, _OnHelp) + NOTIFY_CODE_HANDLER(CDN_INITDONE, _OnInitDone) + NOTIFY_CODE_HANDLER(CDN_SELCHANGE, _OnSelChange) + NOTIFY_CODE_HANDLER(CDN_SHAREVIOLATION, _OnShareViolation) + NOTIFY_CODE_HANDLER(CDN_TYPECHANGE, _OnTypeChange) +#ifndef _WIN32_WCE + NOTIFY_CODE_HANDLER(CDN_INCLUDEITEM, _OnIncludeItem) +#endif // !_WIN32_WCE + END_MSG_MAP() + + LRESULT _OnFileOK(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + return !pT->OnFileOK((LPOFNOTIFY)pnmh); + } + + LRESULT _OnFolderChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnFolderChange((LPOFNOTIFY)pnmh); + return 0; + } + + LRESULT _OnHelp(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnHelp((LPOFNOTIFY)pnmh); + return 0; + } + + LRESULT _OnInitDone(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnInitDone((LPOFNOTIFY)pnmh); + return 0; + } + + LRESULT _OnSelChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnSelChange((LPOFNOTIFY)pnmh); + return 0; + } + + LRESULT _OnShareViolation(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + return pT->OnShareViolation((LPOFNOTIFY)pnmh); + } + + LRESULT _OnTypeChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + pT->OnTypeChange((LPOFNOTIFY)pnmh); + return 0; + } + +#ifndef _WIN32_WCE + LRESULT _OnIncludeItem(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + ATLASSERT(::IsWindow(m_hWnd)); + T* pT = static_cast(this); + return pT->OnIncludeItem((LPOFNOTIFYEX)pnmh); + } +#endif // !_WIN32_WCE + +// Overrideables + BOOL OnFileOK(LPOFNOTIFY /*lpon*/) + { + return TRUE; + } + + void OnFolderChange(LPOFNOTIFY /*lpon*/) + { + } + + void OnHelp(LPOFNOTIFY /*lpon*/) + { + } + + void OnInitDone(LPOFNOTIFY /*lpon*/) + { + } + + void OnSelChange(LPOFNOTIFY /*lpon*/) + { + } + + int OnShareViolation(LPOFNOTIFY /*lpon*/) + { + return 0; + } + + void OnTypeChange(LPOFNOTIFY /*lpon*/) + { + } + +#ifndef _WIN32_WCE + BOOL OnIncludeItem(LPOFNOTIFYEX /*lponex*/) + { + return TRUE; // include item + } +#endif // !_WIN32_WCE +}; + +class CFileDialog : public CFileDialogImpl +{ +public: + CFileDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + : CFileDialogImpl(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent) + { } + + // override base class map and references to handlers + DECLARE_EMPTY_MSG_MAP() +}; + +#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) +class CFileDialogEx : public CFileDialogImpl +{ +public: + CFileDialogEx( // Supports only FileOpen + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + OFN_EXFLAG ExFlags = OFN_EXFLAG_THUMBNAILVIEW, + OFN_SORTORDER dwSortOrder = OFN_SORTORDER_AUTO, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + : CFileDialogImpl(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent) + { + m_ofn.ExFlags = ExFlags; + m_ofn.dwSortOrder = dwSortOrder; + } + + // override base class map and references to handlers + DECLARE_EMPTY_MSG_MAP() +}; +#endif // defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) + + +/////////////////////////////////////////////////////////////////////////////// +// Multi File Dialog - Multi-select File Open dialog + +#ifndef _WIN32_WCE + +// The class dynamically resizes the buffer as the file selection changes +// (as described in Knowledge Base article 131462). It also expands selected +// shortcut files to take into account the full path of the target file. +// Note that this doesn't work on Win9x for the old style dialogs, as well as +// on NT for non-Unicode builds. + +#ifndef _WTL_FIXED_OFN_BUFFER_LENGTH + #define _WTL_FIXED_OFN_BUFFER_LENGTH 0x10000 +#endif + +template +class ATL_NO_VTABLE CMultiFileDialogImpl : public CFileDialogImpl< T > +{ +public: + mutable LPCTSTR m_pNextFile; +#ifndef _UNICODE + bool m_bIsNT; +#endif + + CMultiFileDialogImpl( + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + : CFileDialogImpl(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent), + m_pNextFile(NULL) + { + m_ofn.Flags |= OFN_ALLOWMULTISELECT; // Force multiple selection mode + +#ifndef _UNICODE + OSVERSIONINFO ovi = { sizeof(ovi) }; + ::GetVersionEx(&ovi); + m_bIsNT = (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT); + if (m_bIsNT) + { + // On NT platforms, GetOpenFileNameA thunks to GetOpenFileNameW and there + // is absolutely nothing we can do except to start off with a large buffer. + ATLVERIFY(ResizeFilenameBuffer(_WTL_FIXED_OFN_BUFFER_LENGTH)); + } +#endif + } + + ~CMultiFileDialogImpl() + { + if (m_ofn.lpstrFile != m_szFileName) // Free the buffer if we allocated it + delete[] m_ofn.lpstrFile; + } + +// Operations + // Get the directory that the files were chosen from. + // The function returns the number of characters copied, not including the terminating zero. + // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero. + // If the function fails, the return value is zero. + int GetDirectory(LPTSTR pBuffer, int nBufLen) const + { + if (m_ofn.lpstrFile == NULL) + return 0; + + LPCTSTR pStr = m_ofn.lpstrFile; + int nLength = lstrlen(pStr); + if (pStr[nLength + 1] == 0) + { + // The OFN buffer contains a single item so extract its path. + LPCTSTR pSep = _strrchr(pStr, _T('\\')); + if (pSep != NULL) + nLength = (int)(DWORD_PTR)(pSep - pStr); + } + + int nRet = 0; + if (pBuffer == NULL) // If the buffer is NULL, return the required length + { + nRet = nLength + 1; + } + else if (nBufLen > nLength) + { + SecureHelper::strncpy_x(pBuffer, nBufLen, pStr, nLength); + nRet = nLength; + } + + return nRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + bool GetDirectory(_CSTRING_NS::CString& strDir) const + { + bool bRet = false; + + int nLength = GetDirectory(NULL, 0); + if (nLength > 0) + { + bRet = (GetDirectory(strDir.GetBuffer(nLength), nLength) > 0); + strDir.ReleaseBuffer(nLength - 1); + } + + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + // Get the first filename as a pointer into the buffer. + LPCTSTR GetFirstFileName() const + { + if (m_ofn.lpstrFile == NULL) + return NULL; + + m_pNextFile = NULL; // Reset internal buffer pointer + + LPCTSTR pStr = m_ofn.lpstrFile; + int nLength = lstrlen(pStr); + if (pStr[nLength + 1] != 0) + { + // Multiple items were selected. The first string is the directory, + // so skip forwards to the second string. + pStr += nLength + 1; + + // Set up m_pNext so it points to the second item (or null). + m_pNextFile = pStr; + GetNextFileName(); + } + else + { + // A single item was selected. Skip forward past the path. + LPCTSTR pSep = _strrchr(pStr, _T('\\')); + if (pSep != NULL) + pStr = pSep + 1; + } + + return pStr; + } + + // Get the next filename as a pointer into the buffer. + LPCTSTR GetNextFileName() const + { + if (m_pNextFile == NULL) + return NULL; + + LPCTSTR pStr = m_pNextFile; + // Set "m_pNextFile" to point to the next file name, or null if we + // have reached the last file in the list. + int nLength = lstrlen(pStr); + m_pNextFile = (pStr[nLength + 1] != 0) ? &pStr[nLength + 1] : NULL; + + return pStr; + } + + // Get the first filename as a full path. + // The function returns the number of characters copied, not including the terminating zero. + // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero. + // If the function fails, the return value is zero. + int GetFirstPathName(LPTSTR pBuffer, int nBufLen) const + { + LPCTSTR pStr = GetFirstFileName(); + int nLengthDir = GetDirectory(NULL, 0); + if((pStr == NULL) || (nLengthDir == 0)) + return 0; + + // Figure out the required length. + int nLengthTotal = nLengthDir + lstrlen(pStr); + + int nRet = 0; + if(pBuffer == NULL) // If the buffer is NULL, return the required length + { + nRet = nLengthTotal + 1; + } + else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path + { + GetDirectory(pBuffer, nBufLen); + SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\")); + SecureHelper::strcat_x(pBuffer, nBufLen, pStr); + nRet = nLengthTotal; + } + + return nRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + bool GetFirstPathName(_CSTRING_NS::CString& strPath) const + { + bool bRet = false; + + int nLength = GetFirstPathName(NULL, 0); + if (nLength > 0) + { + bRet = (GetFirstPathName(strPath.GetBuffer(nLength), nLength) > 0); + strPath.ReleaseBuffer(nLength - 1); + } + + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + // Get the next filename as a full path. + // The function returns the number of characters copied, not including the terminating zero. + // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero. + // If the function fails, the return value is zero. + // The internal position marker is moved forward only if the function succeeds and the buffer was large enough. + int GetNextPathName(LPTSTR pBuffer, int nBufLen) const + { + if (m_pNextFile == NULL) + return 0; + + int nRet = 0; + LPCTSTR pStr = m_pNextFile; + // Does the filename contain a backslash? + if (_strrchr(pStr, _T('\\')) != NULL) + { + // Yes, so we'll assume it's a full path. + int nLength = lstrlen(pStr); + + if (pBuffer == NULL) // If the buffer is NULL, return the required length + { + nRet = nLength + 1; + } + else if (nBufLen > nLength) // The buffer is big enough, so go ahead and copy the filename + { + SecureHelper::strcpy_x(pBuffer, nBufLen, GetNextFileName()); + nRet = nBufLen; + } + } + else + { + // The filename is relative, so construct the full path. + int nLengthDir = GetDirectory(NULL, 0); + if (nLengthDir > 0) + { + // Calculate the required space. + int nLengthTotal = nLengthDir + lstrlen(pStr); + + if(pBuffer == NULL) // If the buffer is NULL, return the required length + { + nRet = nLengthTotal + 1; + } + else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path + { + GetDirectory(pBuffer, nBufLen); + SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\")); + SecureHelper::strcat_x(pBuffer, nBufLen, GetNextFileName()); + nRet = nLengthTotal; + } + } + } + + return nRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + bool GetNextPathName(_CSTRING_NS::CString& strPath) const + { + bool bRet = false; + + int nLength = GetNextPathName(NULL, 0); + if (nLength > 0) + { + bRet = (GetNextPathName(strPath.GetBuffer(nLength), nLength) > 0); + strPath.ReleaseBuffer(nLength - 1); + } + + return bRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +// Implementation + bool ResizeFilenameBuffer(DWORD dwLength) + { + if (dwLength > m_ofn.nMaxFile) + { + // Free the old buffer. + if (m_ofn.lpstrFile != m_szFileName) + { + delete[] m_ofn.lpstrFile; + m_ofn.lpstrFile = NULL; + m_ofn.nMaxFile = 0; + } + + // Allocate the new buffer. + LPTSTR lpstrBuff = NULL; + ATLTRY(lpstrBuff = new TCHAR[dwLength]); + if (lpstrBuff != NULL) + { + m_ofn.lpstrFile = lpstrBuff; + m_ofn.lpstrFile[0] = 0; + m_ofn.nMaxFile = dwLength; + } + } + + return (m_ofn.lpstrFile != NULL); + } + + void OnSelChange(LPOFNOTIFY /*lpon*/) + { +#ifndef _UNICODE + // There is no point resizing the buffer in ANSI builds running on NT. + if (m_bIsNT) + return; +#endif + + // Get the buffer length required to hold the spec. + int nLength = GetSpec(NULL, 0); + if (nLength <= 1) + return; // no files are selected, presumably + + // Add room for the directory, and an extra terminating zero. + nLength += GetFolderPath(NULL, 0) + 1; + + if (!ResizeFilenameBuffer(nLength)) + { + ATLASSERT(FALSE); + return; + } + + // If we are not following links then our work is done. + if ((m_ofn.Flags & OFN_NODEREFERENCELINKS) != 0) + return; + + // Get the file spec, which is the text in the edit control. + if (GetSpec(m_ofn.lpstrFile, m_ofn.nMaxFile) <= 0) + return; + + // Get the ID-list of the current folder. + int nBytes = GetFolderIDList(NULL, 0); + CTempBuffer idlist; + idlist.AllocateBytes(nBytes); + if ((nBytes <= 0) || (GetFolderIDList(idlist, nBytes) <= 0)) + return; + + // First bind to the desktop folder, then to the current folder. + ATL::CComPtr pDesktop, pFolder; + if (FAILED(::SHGetDesktopFolder(&pDesktop))) + return; + if (FAILED(pDesktop->BindToObject(idlist, NULL, IID_IShellFolder, (void**)&pFolder))) + return; + + // Work through the file spec, looking for quoted filenames. If we find a shortcut file, then + // we need to add enough extra buffer space to hold its target path. + DWORD nExtraChars = 0; + bool bInsideQuotes = false; + LPCTSTR pAnchor = m_ofn.lpstrFile; + LPCTSTR pChar = m_ofn.lpstrFile; + for ( ; *pChar; ++pChar) + { + // Look for quotation marks. + if (*pChar == _T('\"')) + { + // We are either entering or leaving a passage of quoted text. + bInsideQuotes = !bInsideQuotes; + + // Is it an opening or closing quote? + if (bInsideQuotes) + { + // We found an opening quote, so set "pAnchor" to the following character. + pAnchor = pChar + 1; + } + else // closing quote + { + // Each quoted entity should be shorter than MAX_PATH. + if (pChar - pAnchor >= MAX_PATH) + return; + + // Get the ID-list and attributes of the file. + USES_CONVERSION; + int nFileNameLength = (int)(DWORD_PTR)(pChar - pAnchor); + TCHAR szFileName[MAX_PATH]; + SecureHelper::strncpy_x(szFileName, MAX_PATH, pAnchor, nFileNameLength); + LPITEMIDLIST pidl = NULL; + DWORD dwAttrib = SFGAO_LINK; + if (SUCCEEDED(pFolder->ParseDisplayName(NULL, NULL, T2W(szFileName), NULL, &pidl, &dwAttrib))) + { + // Is it a shortcut file? + if (dwAttrib & SFGAO_LINK) + { + // Bind to its IShellLink interface. + ATL::CComPtr pLink; + if (SUCCEEDED(pFolder->BindToObject(pidl, NULL, IID_IShellLink, (void**)&pLink))) + { + // Get the shortcut's target path. + TCHAR szPath[MAX_PATH]; + if (SUCCEEDED(pLink->GetPath(szPath, MAX_PATH, NULL, 0))) + { + // If the target path is longer than the shortcut name, then add on the number + // of extra characters that are required. + int nNewLength = lstrlen(szPath); + if (nNewLength > nFileNameLength) + nExtraChars += nNewLength - nFileNameLength; + } + } + } + + // Free the ID-list returned by ParseDisplayName. + ::CoTaskMemFree(pidl); + } + } + } + } + + // If we need more space for shortcut targets, then reallocate. + if (nExtraChars > 0) + ATLVERIFY(ResizeFilenameBuffer(m_ofn.nMaxFile + nExtraChars)); + } + + // Helper for _ATM_MIN_CRT + static const TCHAR* _strrchr(const TCHAR* p, TCHAR ch) + { +#ifndef _ATL_MIN_CRT + return _tcsrchr(p, ch); +#else // _ATL_MIN_CRT + const TCHAR* lpsz = NULL; + while (*p != 0) + { + if (*p == ch) + lpsz = p; + p = ::CharNext(p); + } + return lpsz; +#endif // _ATL_MIN_CRT + } +}; + +class CMultiFileDialog : public CMultiFileDialogImpl +{ +public: + CMultiFileDialog( + LPCTSTR lpszDefExt = NULL, + LPCTSTR lpszFileName = NULL, + DWORD dwFlags = OFN_HIDEREADONLY, + LPCTSTR lpszFilter = NULL, + HWND hWndParent = NULL) + : CMultiFileDialogImpl(lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent) + { } + + BEGIN_MSG_MAP(CMultiFileDialog) + CHAIN_MSG_MAP(CMultiFileDialogImpl) + END_MSG_MAP() +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// Shell File Dialog - new Shell File Open and Save dialogs in Vista + +// Note: Use GetPtr() to access dialog interface methods. +// Example: +// CShellFileOpenDialog dlg; +// dlg.GetPtr()->SetTitle(L"MyFileOpenDialog"); + +#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileDialogImpl - base class for CShellFileOpenDialogImpl and CShellFileSaveDialogImpl + +template +class ATL_NO_VTABLE CShellFileDialogImpl : public IFileDialogEvents +{ +public: +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + INT_PTR nRet = -1; + + T* pT = static_cast(this); + if(pT->m_spFileDlg == NULL) + { + ATLASSERT(FALSE); + return nRet; + } + + DWORD dwCookie = 0; + pT->_Advise(dwCookie); + + HRESULT hRet = pT->m_spFileDlg->Show(hWndParent); + if(SUCCEEDED(hRet)) + nRet = IDOK; + else if(hRet == HRESULT_FROM_WIN32(ERROR_CANCELLED)) + nRet = IDCANCEL; + else + ATLASSERT(FALSE); // error + + pT->_Unadvise(dwCookie); + + return nRet; + } + + bool IsNull() const + { + const T* pT = static_cast(this); + return (pT->m_spFileDlg == NULL); + } + +// Operations - get file path after dialog returns + HRESULT GetFilePath(LPWSTR lpstrFilePath, int cchLength) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + ATL::CComPtr spItem; + HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); + + if(SUCCEEDED(hRet)) + hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, lpstrFilePath, cchLength); + + return hRet; + } + + HRESULT GetFileTitle(LPWSTR lpstrFileTitle, int cchLength) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + ATL::CComPtr spItem; + HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); + + if(SUCCEEDED(hRet)) + hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, lpstrFileTitle, cchLength); + + return hRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + HRESULT GetFilePath(_CSTRING_NS::CString& strFilePath) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + ATL::CComPtr spItem; + HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); + + if(SUCCEEDED(hRet)) + hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, strFilePath); + + return hRet; + } + + HRESULT GetFileTitle(_CSTRING_NS::CString& strFileTitle) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + ATL::CComPtr spItem; + HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); + + if(SUCCEEDED(hRet)) + hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, strFileTitle); + + return hRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +// Helpers for IShellItem + static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, LPWSTR lpstr, int cchLength) + { + ATLASSERT(pShellItem != NULL); + + LPWSTR lpstrName = NULL; + HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName); + + if(SUCCEEDED(hRet)) + { + if(lstrlenW(lpstrName) < cchLength) + { + SecureHelper::strcpyW_x(lpstr, cchLength, lpstrName); + } + else + { + ATLASSERT(FALSE); + hRet = DISP_E_BUFFERTOOSMALL; + } + + ::CoTaskMemFree(lpstrName); + } + + return hRet; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, _CSTRING_NS::CString& str) + { + ATLASSERT(pShellItem != NULL); + + LPWSTR lpstrName = NULL; + HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName); + + if(SUCCEEDED(hRet)) + { + str = lpstrName; + ::CoTaskMemFree(lpstrName); + } + + return hRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +// Implementation + void _Advise(DWORD& dwCookie) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + HRESULT hRet = pT->m_spFileDlg->Advise((IFileDialogEvents*)this, &dwCookie); + ATLVERIFY(SUCCEEDED(hRet)); + } + + void _Unadvise(DWORD dwCookie) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + HRESULT hRet = pT->m_spFileDlg->Unadvise(dwCookie); + ATLVERIFY(SUCCEEDED(hRet)); + } + + void _Init(LPCWSTR lpszFileName, DWORD dwOptions, LPCWSTR lpszDefExt, const COMDLG_FILTERSPEC* arrFilterSpec, UINT uFilterSpecCount) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg != NULL); + + HRESULT hRet = E_FAIL; + + if(lpszFileName != NULL) + { + hRet = pT->m_spFileDlg->SetFileName(lpszFileName); + ATLASSERT(SUCCEEDED(hRet)); + } + + hRet = pT->m_spFileDlg->SetOptions(dwOptions); + ATLASSERT(SUCCEEDED(hRet)); + + if(lpszDefExt != NULL) + { + hRet = pT->m_spFileDlg->SetDefaultExtension(lpszDefExt); + ATLASSERT(SUCCEEDED(hRet)); + } + + if(arrFilterSpec != NULL && uFilterSpecCount != 0U) + { + hRet = pT->m_spFileDlg->SetFileTypes(uFilterSpecCount, arrFilterSpec); + ATLASSERT(SUCCEEDED(hRet)); + } + } + +// Implementation - IUnknown interface + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) + { + if(ppvObject == NULL) + return E_POINTER; + + T* pT = static_cast(this); + if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IFileDialogEvents)) + { + *ppvObject = (IFileDialogEvents*)pT; + // AddRef() not needed + return S_OK; + } + + return E_NOINTERFACE; + } + + virtual ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + + virtual ULONG STDMETHODCALLTYPE Release() + { + return 1; + } + +// Implementation - IFileDialogEvents interface + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFileOk(IFileDialog* pfd) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnFileOk(); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChanging(IFileDialog* pfd, IShellItem* psiFolder) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnFolderChanging(psiFolder); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChange(IFileDialog* pfd) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnFolderChange(); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnSelectionChange(IFileDialog* pfd) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnSelectionChange(); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnShareViolation(IFileDialog* pfd, IShellItem* psi, FDE_SHAREVIOLATION_RESPONSE* pResponse) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnShareViolation(psi, pResponse); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnTypeChange(IFileDialog* pfd) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnTypeChange(); + } + + virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnOverwrite(IFileDialog* pfd, IShellItem* psi, FDE_OVERWRITE_RESPONSE* pResponse) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); + pfd; // avoid level 4 warning + return pT->OnOverwrite(psi, pResponse); + } + +// Overrideables - Event handlers + HRESULT OnFileOk() + { + return E_NOTIMPL; + } + + HRESULT OnFolderChanging(IShellItem* /*psiFolder*/) + { + return E_NOTIMPL; + } + + HRESULT OnFolderChange() + { + return E_NOTIMPL; + } + + HRESULT OnSelectionChange() + { + return E_NOTIMPL; + } + + HRESULT OnShareViolation(IShellItem* /*psi*/, FDE_SHAREVIOLATION_RESPONSE* /*pResponse*/) + { + return E_NOTIMPL; + } + + HRESULT OnTypeChange() + { + return E_NOTIMPL; + } + + HRESULT OnOverwrite(IShellItem* /*psi*/, FDE_OVERWRITE_RESPONSE* /*pResponse*/) + { + return E_NOTIMPL; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileOpenDialogImpl - implements new Shell File Open dialog + +template +class ATL_NO_VTABLE CShellFileOpenDialogImpl : public CShellFileDialogImpl< T > +{ +public: + ATL::CComPtr m_spFileDlg; + + CShellFileOpenDialogImpl(LPCWSTR lpszFileName = NULL, + DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, + LPCWSTR lpszDefExt = NULL, + const COMDLG_FILTERSPEC* arrFilterSpec = NULL, + UINT uFilterSpecCount = 0U) + { + HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileOpenDialog); + + if(SUCCEEDED(hRet)) + _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount); + } + + IFileOpenDialog* GetPtr() + { + return m_spFileDlg; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileOpenDialog - new Shell File Open dialog without events + +class CShellFileOpenDialog : public CShellFileOpenDialogImpl +{ +public: + CShellFileOpenDialog(LPCWSTR lpszFileName = NULL, + DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, + LPCWSTR lpszDefExt = NULL, + const COMDLG_FILTERSPEC* arrFilterSpec = NULL, + UINT uFilterSpecCount = 0U) : CShellFileOpenDialogImpl(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount) + { } + +// Implementation (remove _Advise/_Unadvise code using template magic) + void _Advise(DWORD& /*dwCookie*/) + { } + + void _Unadvise(DWORD /*dwCookie*/) + { } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileSaveDialogImpl - implements new Shell File Save dialog + +template +class ATL_NO_VTABLE CShellFileSaveDialogImpl : public CShellFileDialogImpl< T > +{ +public: + ATL::CComPtr m_spFileDlg; + + CShellFileSaveDialogImpl(LPCWSTR lpszFileName = NULL, + DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, + LPCWSTR lpszDefExt = NULL, + const COMDLG_FILTERSPEC* arrFilterSpec = NULL, + UINT uFilterSpecCount = 0U) + { + HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileSaveDialog); + + if(SUCCEEDED(hRet)) + _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount); + } + + IFileSaveDialog* GetPtr() + { + return m_spFileDlg; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CShellFileSaveDialog - new Shell File Save dialog without events + +class CShellFileSaveDialog : public CShellFileSaveDialogImpl +{ +public: + CShellFileSaveDialog(LPCWSTR lpszFileName = NULL, + DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, + LPCWSTR lpszDefExt = NULL, + const COMDLG_FILTERSPEC* arrFilterSpec = NULL, + UINT uFilterSpecCount = 0U) : CShellFileSaveDialogImpl(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount) + { } + +// Implementation (remove _Advise/_Unadvise code using template magic) + void _Advise(DWORD& /*dwCookie*/) + { } + + void _Unadvise(DWORD /*dwCookie*/) + { } +}; + +#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CFolderDialogImpl - used for browsing for a folder + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CFolderDialogImpl +{ +public: + BROWSEINFO m_bi; + LPCTSTR m_lpstrInitialFolder; + LPCITEMIDLIST m_pidlInitialSelection; + bool m_bExpandInitialSelection; + TCHAR m_szFolderDisplayName[MAX_PATH]; + TCHAR m_szFolderPath[MAX_PATH]; + LPITEMIDLIST m_pidlSelected; + HWND m_hWnd; // used only in the callback function + +// Constructor + CFolderDialogImpl(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) : + m_lpstrInitialFolder(NULL), m_pidlInitialSelection(NULL), m_bExpandInitialSelection(false), m_pidlSelected(NULL), m_hWnd(NULL) + { + memset(&m_bi, 0, sizeof(m_bi)); // initialize structure to 0/NULL + + m_bi.hwndOwner = hWndParent; + m_bi.pidlRoot = NULL; + m_bi.pszDisplayName = m_szFolderDisplayName; + m_bi.lpszTitle = lpstrTitle; + m_bi.ulFlags = uFlags; + m_bi.lpfn = BrowseCallbackProc; + m_bi.lParam = (LPARAM)static_cast(this); + + m_szFolderPath[0] = 0; + m_szFolderDisplayName[0] = 0; + } + + ~CFolderDialogImpl() + { + ::CoTaskMemFree(m_pidlSelected); + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + if(m_bi.hwndOwner == NULL) // set only if not specified before + m_bi.hwndOwner = hWndParent; + + // Clear out any previous results + m_szFolderPath[0] = 0; + m_szFolderDisplayName[0] = 0; + ::CoTaskMemFree(m_pidlSelected); + + INT_PTR nRet = IDCANCEL; + m_pidlSelected = ::SHBrowseForFolder(&m_bi); + + if(m_pidlSelected != NULL) + { + nRet = IDOK; + + // If BIF_RETURNONLYFSDIRS is set, we try to get the filesystem path. + // Otherwise, the caller must handle the ID-list directly. + if((m_bi.ulFlags & BIF_RETURNONLYFSDIRS) != 0) + { + if(::SHGetPathFromIDList(m_pidlSelected, m_szFolderPath) == FALSE) + nRet = IDCANCEL; + } + } + + return nRet; + } + + // Methods to call before DoModal + void SetInitialFolder(LPCTSTR lpstrInitialFolder, bool bExpand = true) + { + // lpstrInitialFolder may be a file if BIF_BROWSEINCLUDEFILES is specified + m_lpstrInitialFolder = lpstrInitialFolder; + m_bExpandInitialSelection = bExpand; + } + + void SetInitialSelection(LPCITEMIDLIST pidl, bool bExpand = true) + { + m_pidlInitialSelection = pidl; + m_bExpandInitialSelection = bExpand; + } + + // Methods to call after DoModal + LPITEMIDLIST GetSelectedItem(bool bDetach = false) + { + LPITEMIDLIST pidl = m_pidlSelected; + if(bDetach) + m_pidlSelected = NULL; + + return pidl; + } + + LPCTSTR GetFolderPath() const + { + return m_szFolderPath; + } + + LPCTSTR GetFolderDisplayName() const + { + return m_szFolderDisplayName; + } + + int GetFolderImageIndex() const + { + return m_bi.iImage; + } + +// Callback function and overrideables + static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData) + { +#ifndef BFFM_VALIDATEFAILED + #ifdef UNICODE + const int BFFM_VALIDATEFAILED = 4; + #else + const int BFFM_VALIDATEFAILED = 3; + #endif +#endif // !BFFM_VALIDATEFAILED +#ifndef BFFM_IUNKNOWN + const int BFFM_IUNKNOWN = 5; +#endif // !BFFM_IUNKNOWN +#ifndef BIF_NEWDIALOGSTYLE + const UINT BIF_NEWDIALOGSTYLE = 0x0040; +#endif // !BIF_NEWDIALOGSTYLE + + int nRet = 0; + T* pT = (T*)lpData; + bool bClear = false; + if(pT->m_hWnd == NULL) + { + pT->m_hWnd = hWnd; + bClear = true; + } + else + { + ATLASSERT(pT->m_hWnd == hWnd); + } + + switch(uMsg) + { + case BFFM_INITIALIZED: + // Set initial selection + // Note that m_pidlInitialSelection, if set, takes precedence over m_lpstrInitialFolder + if(pT->m_pidlInitialSelection != NULL) + pT->SetSelection(pT->m_pidlInitialSelection); + else if(pT->m_lpstrInitialFolder != NULL) + pT->SetSelection(pT->m_lpstrInitialFolder); + + // Expand initial selection if appropriate + if(pT->m_bExpandInitialSelection && ((pT->m_bi.ulFlags & BIF_NEWDIALOGSTYLE) != 0)) + { + if(pT->m_pidlInitialSelection != NULL) + pT->SetExpanded(pT->m_pidlInitialSelection); + else if(pT->m_lpstrInitialFolder != NULL) + pT->SetExpanded(pT->m_lpstrInitialFolder); + } + pT->OnInitialized(); + break; + case BFFM_SELCHANGED: + pT->OnSelChanged((LPITEMIDLIST)lParam); + break; + case BFFM_VALIDATEFAILED: + nRet = pT->OnValidateFailed((LPCTSTR)lParam); + break; + case BFFM_IUNKNOWN: + pT->OnIUnknown((IUnknown*)lParam); + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("Unknown message received in CFolderDialogImpl::BrowseCallbackProc\n")); + break; + } + + if(bClear) + pT->m_hWnd = NULL; + return nRet; + } + + void OnInitialized() + { + } + + void OnSelChanged(LPITEMIDLIST /*pItemIDList*/) + { + } + + int OnValidateFailed(LPCTSTR /*lpstrFolderPath*/) + { + return 1; // 1=continue, 0=EndDialog + } + + void OnIUnknown(IUnknown* /*pUnknown*/) + { + } + + // Commands - valid to call only from handlers + void EnableOK(BOOL bEnable) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_ENABLEOK, 0, bEnable); + } + + void SetSelection(LPCITEMIDLIST pItemIDList) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_SETSELECTION, FALSE, (LPARAM)pItemIDList); + } + + void SetSelection(LPCTSTR lpstrFolderPath) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrFolderPath); + } + + void SetStatusText(LPCTSTR lpstrText) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)lpstrText); + } + + void SetOKText(LPCTSTR lpstrOKText) + { +#ifndef BFFM_SETOKTEXT + const UINT BFFM_SETOKTEXT = WM_USER + 105; +#endif + ATLASSERT(m_hWnd != NULL); + USES_CONVERSION; + LPCWSTR lpstr = T2CW(lpstrOKText); + ::SendMessage(m_hWnd, BFFM_SETOKTEXT, (WPARAM)lpstr, 0L); + } + + void SetExpanded(LPCITEMIDLIST pItemIDList) + { +#ifndef BFFM_SETEXPANDED + const UINT BFFM_SETEXPANDED = WM_USER + 106; +#endif + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, BFFM_SETEXPANDED, FALSE, (LPARAM)pItemIDList); + } + + void SetExpanded(LPCTSTR lpstrFolderPath) + { +#ifndef BFFM_SETEXPANDED + const UINT BFFM_SETEXPANDED = WM_USER + 106; +#endif + ATLASSERT(m_hWnd != NULL); + USES_CONVERSION; + LPCWSTR lpstr = T2CW(lpstrFolderPath); + ::SendMessage(m_hWnd, BFFM_SETEXPANDED, TRUE, (LPARAM)lpstr); + } +}; + +class CFolderDialog : public CFolderDialogImpl +{ +public: + CFolderDialog(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) + : CFolderDialogImpl(hWndParent, lpstrTitle, uFlags) + { } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CCommonDialogImplBase - base class for common dialog classes + +class ATL_NO_VTABLE CCommonDialogImplBase : public ATL::CWindowImplBase +{ +public: + static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + if(uMsg != WM_INITDIALOG) + return 0; + CCommonDialogImplBase* pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData(); + ATLASSERT(pT != NULL); + ATLASSERT(pT->m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); + // subclass dialog's window + if(!pT->SubclassWindow(hWnd)) + { + ATLTRACE2(atlTraceUI, 0, _T("Subclassing a common dialog failed\n")); + return 0; + } + // check message map for WM_INITDIALOG handler + LRESULT lRes = 0; + if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE) + return 0; + return lRes; + } + +// Special override for common dialogs + BOOL EndDialog(INT_PTR /*nRetCode*/ = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0)); + return TRUE; + } + +// Implementation - try to override these, to prevent errors + HWND Create(HWND, ATL::_U_RECT, LPCTSTR, DWORD, DWORD, ATL::_U_MENUorID, ATOM, LPVOID) + { + ATLASSERT(FALSE); // should not be called + return NULL; + } + + static LRESULT CALLBACK StartWindowProc(HWND /*hWnd*/, UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) + { + ATLASSERT(FALSE); // should not be called + return 0; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CFontDialogImpl - font selection dialog + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CFontDialogImpl : public CCommonDialogImplBase +{ +public: + enum { _cchStyleName = 64 }; + + CHOOSEFONT m_cf; + TCHAR m_szStyleName[_cchStyleName]; // contains style name after return + LOGFONT m_lf; // default LOGFONT to store the info + +// Constructors + CFontDialogImpl(LPLOGFONT lplfInitial = NULL, + DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, + HDC hDCPrinter = NULL, + HWND hWndParent = NULL) + { + memset(&m_cf, 0, sizeof(m_cf)); + memset(&m_lf, 0, sizeof(m_lf)); + memset(&m_szStyleName, 0, sizeof(m_szStyleName)); + + m_cf.lStructSize = sizeof(m_cf); + m_cf.hwndOwner = hWndParent; + m_cf.rgbColors = RGB(0, 0, 0); + m_cf.lpszStyle = (LPTSTR)&m_szStyleName; + m_cf.Flags = dwFlags | CF_ENABLEHOOK; + m_cf.lpfnHook = (LPCFHOOKPROC)T::HookProc; + + if(lplfInitial != NULL) + { + m_cf.lpLogFont = lplfInitial; + m_cf.Flags |= CF_INITTOLOGFONTSTRUCT; + m_lf = *lplfInitial; + } + else + { + m_cf.lpLogFont = &m_lf; + } + + if(hDCPrinter != NULL) + { + m_cf.hDC = hDCPrinter; + m_cf.Flags |= CF_PRINTERFONTS; + } + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_cf.Flags & CF_ENABLEHOOK) != 0); + ATLASSERT(m_cf.lpfnHook != NULL); // can still be a user hook + + if(m_cf.hwndOwner == NULL) // set only if not specified before + m_cf.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + BOOL bRet = ::ChooseFont(&m_cf); + + m_hWnd = NULL; + + if(bRet) // copy logical font from user's initialization buffer (if needed) + SecureHelper::memcpy_x(&m_lf, sizeof(m_lf), m_cf.lpLogFont, sizeof(m_lf)); + + return bRet ? IDOK : IDCANCEL; + } + + // works only when the dialog is dislayed or after + void GetCurrentFont(LPLOGFONT lplf) const + { + ATLASSERT(lplf != NULL); + + if(m_hWnd != NULL) + ::SendMessage(m_hWnd, WM_CHOOSEFONT_GETLOGFONT, 0, (LPARAM)lplf); + else + *lplf = m_lf; + } + + // works only when the dialog is dislayed or before +#ifndef _WIN32_WCE + void SetLogFont(LPLOGFONT lplf) + { + ATLASSERT(lplf != NULL); +#ifndef WM_CHOOSEFONT_SETLOGFONT + const UINT WM_CHOOSEFONT_SETLOGFONT = (WM_USER + 101); +#endif + if(m_hWnd != NULL) + { + ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETLOGFONT, 0, (LPARAM)lplf); + } + else + { + m_lf = *lplf; + m_cf.Flags |= CF_INITTOLOGFONTSTRUCT; + } + } + + void SetFlags(DWORD dwFlags) + { +#ifndef WM_CHOOSEFONT_SETFLAGS + const UINT WM_CHOOSEFONT_SETFLAGS = (WM_USER + 102); +#endif + if(m_hWnd != NULL) + { + CHOOSEFONT cf = { sizeof(CHOOSEFONT) }; + cf.Flags = dwFlags; + ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETFLAGS, 0, (LPARAM)&cf); + } + else + { + m_cf.Flags = dwFlags; + } + } +#endif // !_WIN32_WCE + + // Helpers for parsing information after successful return + LPCTSTR GetFaceName() const // return the face name of the font + { + return (LPCTSTR)m_cf.lpLogFont->lfFaceName; + } + + LPCTSTR GetStyleName() const // return the style name of the font + { + return m_cf.lpszStyle; + } + + int GetSize() const // return the pt size of the font + { + return m_cf.iPointSize; + } + + COLORREF GetColor() const // return the color of the font + { + return m_cf.rgbColors; + } + + int GetWeight() const // return the chosen font weight + { + return (int)m_cf.lpLogFont->lfWeight; + } + + BOOL IsStrikeOut() const // return TRUE if strikeout + { + return (m_cf.lpLogFont->lfStrikeOut) ? TRUE : FALSE; + } + + BOOL IsUnderline() const // return TRUE if underline + { + return (m_cf.lpLogFont->lfUnderline) ? TRUE : FALSE; + } + + BOOL IsBold() const // return TRUE if bold font + { + return (m_cf.lpLogFont->lfWeight == FW_BOLD) ? TRUE : FALSE; + } + + BOOL IsItalic() const // return TRUE if italic font + { + return m_cf.lpLogFont->lfItalic ? TRUE : FALSE; + } +}; + +class CFontDialog : public CFontDialogImpl +{ +public: + CFontDialog(LPLOGFONT lplfInitial = NULL, + DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, + HDC hDCPrinter = NULL, + HWND hWndParent = NULL) + : CFontDialogImpl(lplfInitial, dwFlags, hDCPrinter, hWndParent) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CRichEditFontDialogImpl - font selection for the Rich Edit ctrl + +#if defined(_RICHEDIT_) && !defined(_WIN32_WCE) + +template +class ATL_NO_VTABLE CRichEditFontDialogImpl : public CFontDialogImpl< T > +{ +public: + CRichEditFontDialogImpl(const CHARFORMAT& charformat, + DWORD dwFlags = CF_SCREENFONTS, + HDC hDCPrinter = NULL, + HWND hWndParent = NULL) + : CFontDialogImpl< T >(NULL, dwFlags, hDCPrinter, hWndParent) + { + m_cf.Flags |= CF_INITTOLOGFONTSTRUCT; + m_cf.Flags |= FillInLogFont(charformat); + m_cf.lpLogFont = &m_lf; + + if((charformat.dwMask & CFM_COLOR) != 0) + m_cf.rgbColors = charformat.crTextColor; + } + + void GetCharFormat(CHARFORMAT& cf) const + { + USES_CONVERSION; + cf.dwEffects = 0; + cf.dwMask = 0; + if((m_cf.Flags & CF_NOSTYLESEL) == 0) + { + cf.dwMask |= CFM_BOLD | CFM_ITALIC; + cf.dwEffects |= IsBold() ? CFE_BOLD : 0; + cf.dwEffects |= IsItalic() ? CFE_ITALIC : 0; + } + if((m_cf.Flags & CF_NOSIZESEL) == 0) + { + cf.dwMask |= CFM_SIZE; + // GetSize() returns in tenths of points so mulitply by 2 to get twips + cf.yHeight = GetSize() * 2; + } + + if((m_cf.Flags & CF_NOFACESEL) == 0) + { + cf.dwMask |= CFM_FACE; + cf.bPitchAndFamily = m_cf.lpLogFont->lfPitchAndFamily; +#if (_RICHEDIT_VER >= 0x0200) + SecureHelper::strcpy_x(cf.szFaceName, _countof(cf.szFaceName), GetFaceName()); +#else // !(_RICHEDIT_VER >= 0x0200) + SecureHelper::strcpyA_x(cf.szFaceName, _countof(cf.szFaceName), T2A((LPTSTR)(LPCTSTR)GetFaceName())); +#endif // !(_RICHEDIT_VER >= 0x0200) + } + + if((m_cf.Flags & CF_EFFECTS) != 0) + { + cf.dwMask |= CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR; + cf.dwEffects |= IsUnderline() ? CFE_UNDERLINE : 0; + cf.dwEffects |= IsStrikeOut() ? CFE_STRIKEOUT : 0; + cf.crTextColor = GetColor(); + } + if((m_cf.Flags & CF_NOSCRIPTSEL) == 0) + { + cf.bCharSet = m_cf.lpLogFont->lfCharSet; + cf.dwMask |= CFM_CHARSET; + } + cf.yOffset = 0; + } + + DWORD FillInLogFont(const CHARFORMAT& cf) + { + USES_CONVERSION; + DWORD dwFlags = 0; + if((cf.dwMask & CFM_SIZE) != 0) + { + HDC hDC = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL); + LONG yPerInch = ::GetDeviceCaps(hDC, LOGPIXELSY); + m_lf.lfHeight = -(int)((cf.yHeight * yPerInch) / 1440); + } + else + m_lf.lfHeight = 0; + + m_lf.lfWidth = 0; + m_lf.lfEscapement = 0; + m_lf.lfOrientation = 0; + + if((cf.dwMask & (CFM_ITALIC | CFM_BOLD)) == (CFM_ITALIC | CFM_BOLD)) + { + m_lf.lfWeight = ((cf.dwEffects & CFE_BOLD) != 0) ? FW_BOLD : FW_NORMAL; + m_lf.lfItalic = (BYTE)(((cf.dwEffects & CFE_ITALIC) != 0) ? TRUE : FALSE); + } + else + { + dwFlags |= CF_NOSTYLESEL; + m_lf.lfWeight = FW_DONTCARE; + m_lf.lfItalic = FALSE; + } + + if((cf.dwMask & (CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR)) == (CFM_UNDERLINE|CFM_STRIKEOUT|CFM_COLOR)) + { + dwFlags |= CF_EFFECTS; + m_lf.lfUnderline = (BYTE)(((cf.dwEffects & CFE_UNDERLINE) != 0) ? TRUE : FALSE); + m_lf.lfStrikeOut = (BYTE)(((cf.dwEffects & CFE_STRIKEOUT) != 0) ? TRUE : FALSE); + } + else + { + m_lf.lfUnderline = (BYTE)FALSE; + m_lf.lfStrikeOut = (BYTE)FALSE; + } + + if((cf.dwMask & CFM_CHARSET) != 0) + m_lf.lfCharSet = cf.bCharSet; + else + dwFlags |= CF_NOSCRIPTSEL; + m_lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + m_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + m_lf.lfQuality = DEFAULT_QUALITY; + if((cf.dwMask & CFM_FACE) != 0) + { + m_lf.lfPitchAndFamily = cf.bPitchAndFamily; +#if (_RICHEDIT_VER >= 0x0200) + SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), cf.szFaceName); +#else // !(_RICHEDIT_VER >= 0x0200) + SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), A2T((LPSTR)cf.szFaceName)); +#endif // !(_RICHEDIT_VER >= 0x0200) + } + else + { + m_lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; + m_lf.lfFaceName[0] = (TCHAR)0; + } + return dwFlags; + } +}; + +class CRichEditFontDialog : public CRichEditFontDialogImpl +{ +public: + CRichEditFontDialog(const CHARFORMAT& charformat, + DWORD dwFlags = CF_SCREENFONTS, + HDC hDCPrinter = NULL, + HWND hWndParent = NULL) + : CRichEditFontDialogImpl(charformat, dwFlags, hDCPrinter, hWndParent) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // defined(_RICHEDIT_) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CColorDialogImpl - color selection + +#if !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500))) + +#ifdef _WIN32_WCE + #pragma comment(lib, "commdlg.lib") + + #ifndef SETRGBSTRING + #define SETRGBSTRING _T("commdlg_SetRGBColor") + #endif + + #ifndef COLOROKSTRING + #define COLOROKSTRING _T("commdlg_ColorOK") + #endif +#endif + +template +class ATL_NO_VTABLE CColorDialogImpl : public CCommonDialogImplBase +{ +public: + CHOOSECOLOR m_cc; + +// Constructor + CColorDialogImpl(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL) + { + memset(&m_cc, 0, sizeof(m_cc)); + + m_cc.lStructSize = sizeof(m_cc); + m_cc.lpCustColors = GetCustomColors(); + m_cc.hwndOwner = hWndParent; + m_cc.Flags = dwFlags | CC_ENABLEHOOK; + m_cc.lpfnHook = (LPCCHOOKPROC)T::HookProc; + + if(clrInit != 0) + { + m_cc.rgbResult = clrInit; + m_cc.Flags |= CC_RGBINIT; + } + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_cc.Flags & CC_ENABLEHOOK) != 0); + ATLASSERT(m_cc.lpfnHook != NULL); // can still be a user hook + + if(m_cc.hwndOwner == NULL) // set only if not specified before + m_cc.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + BOOL bRet = ::ChooseColor(&m_cc); + + m_hWnd = NULL; + + return bRet ? IDOK : IDCANCEL; + } + + // Set the current color while dialog is displayed + void SetCurrentColor(COLORREF clr) + { + ATLASSERT(::IsWindow(m_hWnd)); + SendMessage(_GetSetRGBMessage(), 0, (LPARAM)clr); + } + + // Get the selected color after DoModal returns, or in OnColorOK + COLORREF GetColor() const + { + return m_cc.rgbResult; + } + +// Special override for the color dialog + static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + if(uMsg != WM_INITDIALOG && uMsg != _GetColorOKMessage()) + return 0; + + LPCHOOSECOLOR lpCC = (LPCHOOSECOLOR)lParam; + CCommonDialogImplBase* pT = NULL; + + if(uMsg == WM_INITDIALOG) + { + pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData(); + lpCC->lCustData = (LPARAM)pT; + ATLASSERT(pT != NULL); + ATLASSERT(pT->m_hWnd == NULL); + ATLASSERT(::IsWindow(hWnd)); + // subclass dialog's window + if(!pT->SubclassWindow(hWnd)) + { + ATLTRACE2(atlTraceUI, 0, _T("Subclassing a Color common dialog failed\n")); + return 0; + } + } + else if(uMsg == _GetColorOKMessage()) + { + pT = (CCommonDialogImplBase*)lpCC->lCustData; + ATLASSERT(pT != NULL); + ATLASSERT(::IsWindow(pT->m_hWnd)); + } + + // pass to the message map + LRESULT lRes; + if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE) + return 0; + return lRes; + } + +// Helpers + static COLORREF* GetCustomColors() + { + static COLORREF rgbCustomColors[16] = + { + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + RGB(255, 255, 255), RGB(255, 255, 255), + }; + + return rgbCustomColors; + } + + static UINT _GetSetRGBMessage() + { + static UINT uSetRGBMessage = 0; + if(uSetRGBMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetSetRGBMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uSetRGBMessage == 0) + uSetRGBMessage = ::RegisterWindowMessage(SETRGBSTRING); + + lock.Unlock(); + } + ATLASSERT(uSetRGBMessage != 0); + return uSetRGBMessage; + } + + static UINT _GetColorOKMessage() + { + static UINT uColorOKMessage = 0; + if(uColorOKMessage == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetColorOKMessage.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uColorOKMessage == 0) + uColorOKMessage = ::RegisterWindowMessage(COLOROKSTRING); + + lock.Unlock(); + } + ATLASSERT(uColorOKMessage != 0); + return uColorOKMessage; + } + +// Message map and handlers + BEGIN_MSG_MAP(CColorDialogImpl) + MESSAGE_HANDLER(_GetColorOKMessage(), _OnColorOK) + END_MSG_MAP() + + LRESULT _OnColorOK(UINT, WPARAM, LPARAM, BOOL&) + { + T* pT = static_cast(this); + return pT->OnColorOK(); + } + +// Overrideable + BOOL OnColorOK() // validate color + { + return FALSE; + } +}; + +class CColorDialog : public CColorDialogImpl +{ +public: + CColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL) + : CColorDialogImpl(clrInit, dwFlags, hWndParent) + { } + + // override base class map and references to handlers + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500))) + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintDialogImpl - used for Print... and PrintSetup... + +#ifndef _WIN32_WCE + +// global helper +static HDC _AtlCreateDC(HGLOBAL hDevNames, HGLOBAL hDevMode) +{ + if(hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDevNames = (LPDEVNAMES)::GlobalLock(hDevNames); + LPDEVMODE lpDevMode = (hDevMode != NULL) ? (LPDEVMODE)::GlobalLock(hDevMode) : NULL; + + if(lpDevNames == NULL) + return NULL; + + HDC hDC = ::CreateDC((LPCTSTR)lpDevNames + lpDevNames->wDriverOffset, + (LPCTSTR)lpDevNames + lpDevNames->wDeviceOffset, + (LPCTSTR)lpDevNames + lpDevNames->wOutputOffset, + lpDevMode); + + ::GlobalUnlock(hDevNames); + if(hDevMode != NULL) + ::GlobalUnlock(hDevMode); + return hDC; +} + +template +class ATL_NO_VTABLE CPrintDialogImpl : public CCommonDialogImplBase +{ +public: + // print dialog parameter block (note this is a reference) + PRINTDLG& m_pd; + +// Constructors + CPrintDialogImpl(BOOL bPrintSetupOnly = FALSE, // TRUE for Print Setup, FALSE for Print Dialog + DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION, + HWND hWndParent = NULL) + : m_pd(m_pdActual) + { + memset(&m_pdActual, 0, sizeof(m_pdActual)); + + m_pd.lStructSize = sizeof(m_pdActual); + m_pd.hwndOwner = hWndParent; + m_pd.Flags = (dwFlags | PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK); + m_pd.lpfnPrintHook = (LPPRINTHOOKPROC)T::HookProc; + m_pd.lpfnSetupHook = (LPSETUPHOOKPROC)T::HookProc; + + if(bPrintSetupOnly) + m_pd.Flags |= PD_PRINTSETUP; + else + m_pd.Flags |= PD_RETURNDC; + + m_pd.Flags &= ~PD_RETURNIC; // do not support information context + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_pd.Flags & PD_ENABLEPRINTHOOK) != 0); + ATLASSERT((m_pd.Flags & PD_ENABLESETUPHOOK) != 0); + ATLASSERT(m_pd.lpfnPrintHook != NULL); // can still be a user hook + ATLASSERT(m_pd.lpfnSetupHook != NULL); // can still be a user hook + ATLASSERT((m_pd.Flags & PD_RETURNDEFAULT) == 0); // use GetDefaults for this + + if(m_pd.hwndOwner == NULL) // set only if not specified before + m_pd.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + BOOL bRet = ::PrintDlg(&m_pd); + + m_hWnd = NULL; + + return bRet ? IDOK : IDCANCEL; + } + + // GetDefaults will not display a dialog but will get device defaults + BOOL GetDefaults() + { + m_pd.Flags |= PD_RETURNDEFAULT; + ATLASSERT(m_pd.hDevMode == NULL); // must be NULL + ATLASSERT(m_pd.hDevNames == NULL); // must be NULL + + return ::PrintDlg(&m_pd); + } + + // Helpers for parsing information after successful return num. copies requested + int GetCopies() const + { + if((m_pd.Flags & PD_USEDEVMODECOPIES) != 0) + { + LPDEVMODE lpDevMode = GetDevMode(); + return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1; + } + + return m_pd.nCopies; + } + + BOOL PrintCollate() const // TRUE if collate checked + { + return ((m_pd.Flags & PD_COLLATE) != 0) ? TRUE : FALSE; + } + + BOOL PrintSelection() const // TRUE if printing selection + { + return ((m_pd.Flags & PD_SELECTION) != 0) ? TRUE : FALSE; + } + + BOOL PrintAll() const // TRUE if printing all pages + { + return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE; + } + + BOOL PrintRange() const // TRUE if printing page range + { + return ((m_pd.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE; + } + + BOOL PrintToFile() const // TRUE if printing to a file + { + return ((m_pd.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE; + } + + int GetFromPage() const // starting page if valid + { + return PrintRange() ? m_pd.nFromPage : -1; + } + + int GetToPage() const // ending page if valid + { + return PrintRange() ? m_pd.nToPage : -1; + } + + LPDEVMODE GetDevMode() const // return DEVMODE + { + if(m_pd.hDevMode == NULL) + return NULL; + + return (LPDEVMODE)::GlobalLock(m_pd.hDevMode); + } + + LPCTSTR GetDriverName() const // return driver name + { + if(m_pd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wDriverOffset; + } + + LPCTSTR GetDeviceName() const // return device name + { + if(m_pd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wDeviceOffset; + } + + LPCTSTR GetPortName() const // return output port name + { + if(m_pd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wOutputOffset; + } + + HDC GetPrinterDC() const // return HDC (caller must delete) + { + ATLASSERT((m_pd.Flags & PD_RETURNDC) != 0); + return m_pd.hDC; + } + + // This helper creates a DC based on the DEVNAMES and DEVMODE structures. + // This DC is returned, but also stored in m_pd.hDC as though it had been + // returned by CommDlg. It is assumed that any previously obtained DC + // has been/will be deleted by the user. This may be + // used without ever invoking the print/print setup dialogs. + HDC CreatePrinterDC() + { + m_pd.hDC = _AtlCreateDC(m_pd.hDevNames, m_pd.hDevMode); + return m_pd.hDC; + } + +// Implementation + PRINTDLG m_pdActual; // the Print/Print Setup need to share this + + // The following handle the case of print setup... from the print dialog + CPrintDialogImpl(PRINTDLG& pdInit) : m_pd(pdInit) + { } + + BEGIN_MSG_MAP(CPrintDialogImpl) +#ifdef psh1 + COMMAND_ID_HANDLER(psh1, OnPrintSetup) // print setup button when print is displayed +#else // !psh1 + COMMAND_ID_HANDLER(0x0400, OnPrintSetup) // value from dlgs.h +#endif // !psh1 + END_MSG_MAP() + + LRESULT OnPrintSetup(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/) + { + T dlgSetup(m_pd); + ModuleHelper::AddCreateWndData(&dlgSetup.m_thunk.cd, (CCommonDialogImplBase*)&dlgSetup); + return DefWindowProc(WM_COMMAND, MAKEWPARAM(wID, wNotifyCode), (LPARAM)hWndCtl); + } +}; + +class CPrintDialog : public CPrintDialogImpl +{ +public: + CPrintDialog(BOOL bPrintSetupOnly = FALSE, + DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION, + HWND hWndParent = NULL) + : CPrintDialogImpl(bPrintSetupOnly, dwFlags, hWndParent) + { } + + CPrintDialog(PRINTDLG& pdInit) : CPrintDialogImpl(pdInit) + { } +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintDialogExImpl - new print dialog for Windows 2000 + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + +}; // namespace WTL + +#include + +extern "C" const __declspec(selectany) IID IID_IPrintDialogCallback = {0x5852a2c3, 0x6530, 0x11d1, {0xb6, 0xa3, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}}; +extern "C" const __declspec(selectany) IID IID_IPrintDialogServices = {0x509aaeda, 0x5639, 0x11d1, {0xb6, 0xa1, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}}; + +namespace WTL +{ + +template +class ATL_NO_VTABLE CPrintDialogExImpl : + public ATL::CWindow, + public ATL::CMessageMap, + public IPrintDialogCallback, + public ATL::IObjectWithSiteImpl< T > +{ +public: + PRINTDLGEX m_pdex; + +// Constructor + CPrintDialogExImpl(DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE, + HWND hWndParent = NULL) + { + memset(&m_pdex, 0, sizeof(m_pdex)); + + m_pdex.lStructSize = sizeof(PRINTDLGEX); + m_pdex.hwndOwner = hWndParent; + m_pdex.Flags = dwFlags; + m_pdex.nStartPage = START_PAGE_GENERAL; + // callback object will be set in DoModal + + m_pdex.Flags &= ~PD_RETURNIC; // do not support information context + } + +// Operations + HRESULT DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT(m_hWnd == NULL); + ATLASSERT((m_pdex.Flags & PD_RETURNDEFAULT) == 0); // use GetDefaults for this + + if(m_pdex.hwndOwner == NULL) // set only if not specified before + m_pdex.hwndOwner = hWndParent; + + T* pT = static_cast(this); + m_pdex.lpCallback = (IUnknown*)(IPrintDialogCallback*)pT; + + HRESULT hResult = ::PrintDlgEx(&m_pdex); + + m_hWnd = NULL; + + return hResult; + } + + BOOL EndDialog(INT_PTR /*nRetCode*/ = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0)); + return TRUE; + } + + // GetDefaults will not display a dialog but will get device defaults + HRESULT GetDefaults() + { + m_pdex.Flags |= PD_RETURNDEFAULT; + ATLASSERT(m_pdex.hDevMode == NULL); // must be NULL + ATLASSERT(m_pdex.hDevNames == NULL); // must be NULL + + return ::PrintDlgEx(&m_pdex); + } + + // Helpers for parsing information after successful return num. copies requested + int GetCopies() const + { + if((m_pdex.Flags & PD_USEDEVMODECOPIES) != 0) + { + LPDEVMODE lpDevMode = GetDevMode(); + return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1; + } + + return m_pdex.nCopies; + } + + BOOL PrintCollate() const // TRUE if collate checked + { + return ((m_pdex.Flags & PD_COLLATE) != 0) ? TRUE : FALSE; + } + + BOOL PrintSelection() const // TRUE if printing selection + { + return ((m_pdex.Flags & PD_SELECTION) != 0) ? TRUE : FALSE; + } + + BOOL PrintAll() const // TRUE if printing all pages + { + return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE; + } + + BOOL PrintRange() const // TRUE if printing page range + { + return ((m_pdex.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE; + } + + BOOL PrintToFile() const // TRUE if printing to a file + { + return ((m_pdex.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE; + } + + LPDEVMODE GetDevMode() const // return DEVMODE + { + if(m_pdex.hDevMode == NULL) + return NULL; + + return (LPDEVMODE)::GlobalLock(m_pdex.hDevMode); + } + + LPCTSTR GetDriverName() const // return driver name + { + if(m_pdex.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wDriverOffset; + } + + LPCTSTR GetDeviceName() const // return device name + { + if(m_pdex.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wDeviceOffset; + } + + LPCTSTR GetPortName() const // return output port name + { + if(m_pdex.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames); + if(lpDev == NULL) + return NULL; + + return (LPCTSTR)lpDev + lpDev->wOutputOffset; + } + + HDC GetPrinterDC() const // return HDC (caller must delete) + { + ATLASSERT((m_pdex.Flags & PD_RETURNDC) != 0); + return m_pdex.hDC; + } + + // This helper creates a DC based on the DEVNAMES and DEVMODE structures. + // This DC is returned, but also stored in m_pdex.hDC as though it had been + // returned by CommDlg. It is assumed that any previously obtained DC + // has been/will be deleted by the user. This may be + // used without ever invoking the print/print setup dialogs. + HDC CreatePrinterDC() + { + m_pdex.hDC = _AtlCreateDC(m_pdex.hDevNames, m_pdex.hDevMode); + return m_pdex.hDC; + } + +// Implementation - interfaces + +// IUnknown + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) + { + if(ppvObject == NULL) + return E_POINTER; + + T* pT = static_cast(this); + if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IPrintDialogCallback)) + { + *ppvObject = (IPrintDialogCallback*)pT; + // AddRef() not needed + return S_OK; + } + else if(IsEqualGUID(riid, IID_IObjectWithSite)) + { + *ppvObject = (IObjectWithSite*)pT; + // AddRef() not needed + return S_OK; + } + + return E_NOINTERFACE; + } + + virtual ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + + virtual ULONG STDMETHODCALLTYPE Release() + { + return 1; + } + +// IPrintDialogCallback + STDMETHOD(InitDone)() + { + return S_FALSE; + } + + STDMETHOD(SelectionChange)() + { + return S_FALSE; + } + + STDMETHOD(HandleMessage)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult) + { + // set up m_hWnd the first time + if(m_hWnd == NULL) + Attach(hWnd); + + // call message map + HRESULT hRet = ProcessWindowMessage(hWnd, uMsg, wParam, lParam, *plResult, 0) ? S_OK : S_FALSE; + if(hRet == S_OK && uMsg == WM_NOTIFY) // return in DWLP_MSGRESULT + ::SetWindowLongPtr(GetParent(), DWLP_MSGRESULT, (LONG_PTR)*plResult); + + if(uMsg == WM_INITDIALOG && hRet == S_OK && (BOOL)*plResult != FALSE) + hRet = S_FALSE; + + return hRet; + } +}; + +class CPrintDialogEx : public CPrintDialogExImpl +{ +public: + CPrintDialogEx( + DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE, + HWND hWndParent = NULL) + : CPrintDialogExImpl(dwFlags, hWndParent) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CPageSetupDialogImpl - Page Setup dialog + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CPageSetupDialogImpl : public CCommonDialogImplBase +{ +public: + PAGESETUPDLG m_psd; + ATL::CWndProcThunk m_thunkPaint; + +// Constructors + CPageSetupDialogImpl(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL) + { + memset(&m_psd, 0, sizeof(m_psd)); + + m_psd.lStructSize = sizeof(m_psd); + m_psd.hwndOwner = hWndParent; + m_psd.Flags = (dwFlags | PSD_ENABLEPAGESETUPHOOK | PSD_ENABLEPAGEPAINTHOOK); + m_psd.lpfnPageSetupHook = (LPPAGESETUPHOOK)T::HookProc; + m_thunkPaint.Init((WNDPROC)T::PaintHookProc, this); +#if (_ATL_VER >= 0x0700) + m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)m_thunkPaint.GetWNDPROC(); +#else + m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)&(m_thunkPaint.thunk); +#endif + } + + DECLARE_EMPTY_MSG_MAP() + +// Attributes + LPDEVMODE GetDevMode() const // return DEVMODE + { + if(m_psd.hDevMode == NULL) + return NULL; + + return (LPDEVMODE)::GlobalLock(m_psd.hDevMode); + } + + LPCTSTR GetDriverName() const // return driver name + { + if(m_psd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames); + return (LPCTSTR)lpDev + lpDev->wDriverOffset; + } + + LPCTSTR GetDeviceName() const // return device name + { + if(m_psd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames); + return (LPCTSTR)lpDev + lpDev->wDeviceOffset; + } + + LPCTSTR GetPortName() const // return output port name + { + if(m_psd.hDevNames == NULL) + return NULL; + + LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames); + return (LPCTSTR)lpDev + lpDev->wOutputOffset; + } + + HDC CreatePrinterDC() + { + return _AtlCreateDC(m_psd.hDevNames, m_psd.hDevMode); + } + + SIZE GetPaperSize() const + { + SIZE size; + size.cx = m_psd.ptPaperSize.x; + size.cy = m_psd.ptPaperSize.y; + return size; + } + + void GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const + { + if(lpRectMargins != NULL) + *lpRectMargins = m_psd.rtMargin; + if(lpRectMinMargins != NULL) + *lpRectMinMargins = m_psd.rtMinMargin; + } + +// Operations + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT((m_psd.Flags & PSD_ENABLEPAGESETUPHOOK) != 0); + ATLASSERT((m_psd.Flags & PSD_ENABLEPAGEPAINTHOOK) != 0); + ATLASSERT(m_psd.lpfnPageSetupHook != NULL); // can still be a user hook + ATLASSERT(m_psd.lpfnPagePaintHook != NULL); // can still be a user hook + + if(m_psd.hwndOwner == NULL) // set only if not specified before + m_psd.hwndOwner = hWndParent; + + ATLASSERT(m_hWnd == NULL); + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + BOOL bRet = ::PageSetupDlg(&m_psd); + + m_hWnd = NULL; + + return bRet ? IDOK : IDCANCEL; + } + +// Implementation + static UINT_PTR CALLBACK PaintHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + T* pT = (T*)hWnd; + UINT_PTR uRet = 0; + switch(uMsg) + { + case WM_PSD_PAGESETUPDLG: + uRet = pT->PreDrawPage(LOWORD(wParam), HIWORD(wParam), (LPPAGESETUPDLG)lParam); + break; + case WM_PSD_FULLPAGERECT: + case WM_PSD_MINMARGINRECT: + case WM_PSD_MARGINRECT: + case WM_PSD_GREEKTEXTRECT: + case WM_PSD_ENVSTAMPRECT: + case WM_PSD_YAFULLPAGERECT: + uRet = pT->OnDrawPage(uMsg, (HDC)wParam, (LPRECT)lParam); + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("CPageSetupDialogImpl::PaintHookProc - unknown message received\n")); + break; + } + return uRet; + } + +// Overridables + UINT_PTR PreDrawPage(WORD /*wPaper*/, WORD /*wFlags*/, LPPAGESETUPDLG /*pPSD*/) + { + // return 1 to prevent any more drawing + return 0; + } + + UINT_PTR OnDrawPage(UINT /*uMsg*/, HDC /*hDC*/, LPRECT /*lpRect*/) + { + return 0; // do the default + } +}; + +class CPageSetupDialog : public CPageSetupDialogImpl +{ +public: + CPageSetupDialog(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL) + : CPageSetupDialogImpl(dwFlags, hWndParent) + { } + + // override PaintHookProc and references to handlers + static UINT_PTR CALLBACK PaintHookProc(HWND, UINT, WPARAM, LPARAM) + { + return 0; + } +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CFindReplaceDialogImpl - Find/FindReplace modeless dialogs + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CFindReplaceDialogImpl : public CCommonDialogImplBase +{ +public: + enum { _cchFindReplaceBuffer = 128 }; + + FINDREPLACE m_fr; + TCHAR m_szFindWhat[_cchFindReplaceBuffer]; + TCHAR m_szReplaceWith[_cchFindReplaceBuffer]; + +// Constructors + CFindReplaceDialogImpl() + { + memset(&m_fr, 0, sizeof(m_fr)); + m_szFindWhat[0] = _T('\0'); + m_szReplaceWith[0] = _T('\0'); + + m_fr.lStructSize = sizeof(m_fr); + m_fr.Flags = FR_ENABLEHOOK; + m_fr.lpfnHook = (LPFRHOOKPROC)T::HookProc; + m_fr.lpstrFindWhat = (LPTSTR)m_szFindWhat; + m_fr.wFindWhatLen = _cchFindReplaceBuffer; + m_fr.lpstrReplaceWith = (LPTSTR)m_szReplaceWith; + m_fr.wReplaceWithLen = _cchFindReplaceBuffer; + } + + // Note: You must allocate the object on the heap. + // If you do not, you must override OnFinalMessage() + virtual void OnFinalMessage(HWND /*hWnd*/) + { + delete this; + } + + HWND Create(BOOL bFindDialogOnly, // TRUE for Find, FALSE for FindReplace + LPCTSTR lpszFindWhat, + LPCTSTR lpszReplaceWith = NULL, + DWORD dwFlags = FR_DOWN, + HWND hWndParent = NULL) + { + ATLASSERT((m_fr.Flags & FR_ENABLEHOOK) != 0); + ATLASSERT(m_fr.lpfnHook != NULL); + + m_fr.Flags |= dwFlags; + + if(hWndParent == NULL) + m_fr.hwndOwner = ::GetActiveWindow(); + else + m_fr.hwndOwner = hWndParent; + ATLASSERT(m_fr.hwndOwner != NULL); // must have an owner for modeless dialog + + if(lpszFindWhat != NULL) + SecureHelper::strncpy_x(m_szFindWhat, _countof(m_szFindWhat), lpszFindWhat, _TRUNCATE); + + if(lpszReplaceWith != NULL) + SecureHelper::strncpy_x(m_szReplaceWith, _countof(m_szReplaceWith), lpszReplaceWith, _TRUNCATE); + + ATLASSERT(m_hWnd == NULL); + ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); + + HWND hWnd = NULL; + if(bFindDialogOnly) + hWnd = ::FindText(&m_fr); + else + hWnd = ::ReplaceText(&m_fr); + + ATLASSERT(m_hWnd == hWnd); + return hWnd; + } + + static const UINT GetFindReplaceMsg() + { + static const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING); + return nMsgFindReplace; + } + // call while handling FINDMSGSTRING registered message + // to retreive the object + static T* PASCAL GetNotifier(LPARAM lParam) + { + ATLASSERT(lParam != NULL); + T* pDlg = (T*)(lParam - offsetof(T, m_fr)); + return pDlg; + } + +// Operations + // Helpers for parsing information after successful return + LPCTSTR GetFindString() const // get find string + { + return (LPCTSTR)m_fr.lpstrFindWhat; + } + + LPCTSTR GetReplaceString() const // get replacement string + { + return (LPCTSTR)m_fr.lpstrReplaceWith; + } + + BOOL SearchDown() const // TRUE if search down, FALSE is up + { + return ((m_fr.Flags & FR_DOWN) != 0) ? TRUE : FALSE; + } + + BOOL FindNext() const // TRUE if command is find next + { + return ((m_fr.Flags & FR_FINDNEXT) != 0) ? TRUE : FALSE; + } + + BOOL MatchCase() const // TRUE if matching case + { + return ((m_fr.Flags & FR_MATCHCASE) != 0) ? TRUE : FALSE; + } + + BOOL MatchWholeWord() const // TRUE if matching whole words only + { + return ((m_fr.Flags & FR_WHOLEWORD) != 0) ? TRUE : FALSE; + } + + BOOL ReplaceCurrent() const // TRUE if replacing current string + { + return ((m_fr. Flags & FR_REPLACE) != 0) ? TRUE : FALSE; + } + + BOOL ReplaceAll() const // TRUE if replacing all occurrences + { + return ((m_fr.Flags & FR_REPLACEALL) != 0) ? TRUE : FALSE; + } + + BOOL IsTerminating() const // TRUE if terminating dialog + { + return ((m_fr.Flags & FR_DIALOGTERM) != 0) ? TRUE : FALSE ; + } +}; + +class CFindReplaceDialog : public CFindReplaceDialogImpl +{ +public: + DECLARE_EMPTY_MSG_MAP() +}; + +#endif // !_WIN32_WCE + + +#if (_ATL_VER >= 0x800) +typedef ATL::_DialogSplitHelper::DLGTEMPLATEEX DLGTEMPLATEEX; +typedef ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX DLGITEMTEMPLATEEX; +#else // (_ATL_VER >= 0x800) +typedef ATL::_DialogSizeHelper::_ATL_DLGTEMPLATEEX DLGTEMPLATEEX; +#pragma pack(push, 4) +struct DLGITEMTEMPLATEEX +{ + DWORD helpID; + DWORD exStyle; + DWORD style; + short x; + short y; + short cx; + short cy; + WORD id; +}; +#pragma pack(pop) +#endif // (_ATL_VER >= 0x800) + + +/////////////////////////////////////////////////////////////////////////////// +// CMemDlgTemplate - in-memory dialog template - DLGTEMPLATE or DLGTEMPLATEEX + +class CMemDlgTemplate +{ +public: + enum StdCtrlType + { + CTRL_BUTTON = 0x0080, + CTRL_EDIT = 0x0081, + CTRL_STATIC = 0x0082, + CTRL_LISTBOX = 0x0083, + CTRL_SCROLLBAR = 0x0084, + CTRL_COMBOBOX = 0x0085 + }; + + CMemDlgTemplate() : m_pData(NULL), m_pPtr(NULL), m_cAllocated(0) + { } + + ~CMemDlgTemplate() + { + Reset(); + } + + bool IsValid() const + { + return (m_pData != NULL); + } + + bool IsTemplateEx() const + { + return (IsValid() && ((DLGTEMPLATEEX*)m_pData)->signature == 0xFFFF); + } + + LPDLGTEMPLATE GetTemplatePtr() + { + return reinterpret_cast(m_pData); + } + + DLGTEMPLATEEX* GetTemplateExPtr() + { + return reinterpret_cast(m_pData); + } + + void Reset() + { + if (IsValid()) + ATLVERIFY(::GlobalFree(m_pData) == NULL); + + m_pData = NULL; + m_pPtr = NULL; + m_cAllocated = 0; + } + + void Create(bool bDlgEx, LPCTSTR lpszCaption, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle = 0, DWORD dwExStyle = 0, + LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0, + ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U) + { + // Should have DS_SETFONT style to set the dialog font name and size + if (lpstrFontName != NULL) + { + dwStyle |= DS_SETFONT; + } + else + { + dwStyle &= ~DS_SETFONT; + } + + if (bDlgEx) + { + DLGTEMPLATEEX dlg = {1, 0xFFFF, dwHelpID, dwExStyle, dwStyle, 0, nX, nY, nWidth, nHeight}; + AddData(&dlg, sizeof(dlg)); + } + else + { + DLGTEMPLATE dlg = {dwStyle, dwExStyle, 0, nX, nY, nWidth, nHeight}; + AddData(&dlg, sizeof(dlg)); + } + +#ifndef _WIN32_WCE + if (Menu.m_lpstr == NULL) + { + WORD menuData = 0; + AddData(&menuData, sizeof(WORD)); + } + else if (IS_INTRESOURCE(Menu.m_lpstr)) + { + WORD menuData[] = {0xFFFF, (WORD)Menu.m_lpstr}; + AddData(menuData, sizeof(menuData)); + } + else + { + AddString(Menu.m_lpstr); + } +#else // _WIN32_WCE + // Windows CE doesn't support the addition of menus to a dialog box + ATLASSERT(Menu.m_lpstr == NULL); + Menu.m_lpstr; // avoid level 4 warning + WORD menuData = 0; + AddData(&menuData, sizeof(WORD)); +#endif // _WIN32_WCE + + if (ClassName.m_lpstr == NULL) + { + WORD classData = 0; + AddData(&classData, sizeof(WORD)); + } + else if (IS_INTRESOURCE(ClassName.m_lpstr)) + { + WORD classData[] = {0xFFFF, (WORD)ClassName.m_lpstr}; + AddData(classData, sizeof(classData)); + } + else + { + AddString(ClassName.m_lpstr); + } + + // Set dialog caption + AddString(lpszCaption); + + if (lpstrFontName != NULL) + { + AddData(&wFontSize, sizeof(wFontSize)); + + if (bDlgEx) + { + AddData(&wWeight, sizeof(wWeight)); + AddData(&bItalic, sizeof(bItalic)); + AddData(&bCharset, sizeof(bCharset)); + } + + AddString(lpstrFontName); + } + } + + void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle, DWORD dwExStyle, + ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0) + { + ATLASSERT(IsValid()); + + // DWORD align data + m_pPtr = (LPBYTE)(DWORD_PTR)((DWORD)(DWORD_PTR)(m_pPtr + 3) & (~3)); + + if (IsTemplateEx()) + { + DLGTEMPLATEEX* dlg = (DLGTEMPLATEEX*)m_pData; + dlg->cDlgItems++; + + DLGITEMTEMPLATEEX item = {dwHelpID, ATL::CControlWinTraits::GetWndExStyle(0) | dwExStyle, ATL::CControlWinTraits::GetWndStyle(0) | dwStyle, nX, nY, nWidth, nHeight, wId}; + AddData(&item, sizeof(item)); + } + else + { + LPDLGTEMPLATE dlg = (LPDLGTEMPLATE)m_pData; + dlg->cdit++; + + DLGITEMTEMPLATE item = {ATL::CControlWinTraits::GetWndStyle(0) | dwStyle, ATL::CControlWinTraits::GetWndExStyle(0) | dwExStyle, nX, nY, nWidth, nHeight, wId}; + AddData(&item, sizeof(item)); + } + + ATLASSERT(ClassName.m_lpstr != NULL); + if (IS_INTRESOURCE(ClassName.m_lpstr)) + { + WORD wData[] = {0xFFFF, (WORD)ClassName.m_lpstr}; + AddData(wData, sizeof(wData)); + } + else + { + AddString(ClassName.m_lpstr); + } + + if (Text.m_lpstr == NULL) + { + WORD classData = 0; + AddData(&classData, sizeof(WORD)); + } + else if (IS_INTRESOURCE(Text.m_lpstr)) + { + WORD wData[] = {0xFFFF, (WORD)Text.m_lpstr}; + AddData(wData, sizeof(wData)); + } + else + { + AddString(Text.m_lpstr); + } + + AddData(&nCreationData, sizeof(nCreationData)); + + if ((nCreationData != 0)) + { + ATLASSERT(pCreationData != NULL); + AddData(pCreationData, nCreationData * sizeof(WORD)); + } + } + + void AddStdControl(StdCtrlType CtrlType, WORD wId, short nX, short nY, short nWidth, short nHeight, + DWORD dwStyle, DWORD dwExStyle, ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0) + { + AddControl(CtrlType, wId, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, Text, pCreationData, nCreationData, dwHelpID); + } + +protected: + void AddData(LPCVOID pData, size_t nData) + { + ATLASSERT(pData != NULL); + + const size_t ALLOCATION_INCREMENT = 1024; + + if (m_pData == NULL) + { + m_cAllocated = ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT; + m_pPtr = m_pData = static_cast(::GlobalAlloc(GPTR, m_cAllocated)); + ATLASSERT(m_pData != NULL); + } + else if (((m_pPtr - m_pData) + nData) > m_cAllocated) + { + size_t ptrPos = (m_pPtr - m_pData); + m_cAllocated += ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT; + m_pData = static_cast(::GlobalReAlloc(m_pData, m_cAllocated, 0)); + ATLASSERT(m_pData != NULL); + m_pPtr = m_pData + ptrPos; + } + + SecureHelper::memcpy_x(m_pPtr, m_cAllocated - (m_pPtr - m_pData), pData, nData); + + m_pPtr += nData; + } + + void AddString(LPCTSTR lpszStr) + { + if (lpszStr == NULL) + { + WCHAR szEmpty = 0; + AddData(&szEmpty, sizeof(szEmpty)); + } + else + { + USES_CONVERSION; + LPCWSTR lpstr = T2CW(lpszStr); + int nSize = lstrlenW(lpstr) + 1; + AddData(lpstr, nSize * sizeof(WCHAR)); + } + } + + LPBYTE m_pData; + LPBYTE m_pPtr; + SIZE_T m_cAllocated; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Dialog and control macros for indirect dialogs + +// for DLGTEMPLATE +#define BEGIN_DIALOG(x, y, width, height) \ + void DoInitTemplate() \ + { \ + bool bExTemplate = false; \ + short nX = x, nY = y, nWidth = width, nHeight = height; \ + LPCTSTR szCaption = NULL; \ + DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \ + DWORD dwExStyle = 0; \ + LPCTSTR szFontName = NULL; \ + WORD wFontSize = 0; \ + WORD wWeight = 0; \ + BYTE bItalic = 0; \ + BYTE bCharset = 0; \ + DWORD dwHelpID = 0; \ + ATL::_U_STRINGorID Menu = 0U; \ + ATL::_U_STRINGorID ClassName = 0U; + +// for DLGTEMPLATEEX +#define BEGIN_DIALOG_EX(x, y, width, height, helpID) \ + void DoInitTemplate() \ + { \ + bool bExTemplate = true; \ + short nX = x, nY = y, nWidth = width, nHeight = height; \ + LPCTSTR szCaption = NULL; \ + DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \ + DWORD dwExStyle = 0; \ + LPCTSTR szFontName = NULL; \ + WORD wFontSize = 0; \ + WORD wWeight = 0; \ + BYTE bItalic = 0; \ + BYTE bCharset = 0; \ + DWORD dwHelpID = helpID; \ + ATL::_U_STRINGorID Menu = 0U; \ + ATL::_U_STRINGorID ClassName = 0U; + +#define END_DIALOG() \ + m_Template.Create(bExTemplate, szCaption, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, szFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName, Menu); \ + }; + +#define DIALOG_CAPTION(caption) \ + szCaption = caption; +#define DIALOG_STYLE(style) \ + dwStyle = style; +#define DIALOG_EXSTYLE(exStyle) \ + dwExStyle = exStyle; +#define DIALOG_FONT(pointSize, typeFace) \ + wFontSize = pointSize; \ + szFontName = typeFace; +#define DIALOG_FONT_EX(pointsize, typeface, weight, italic, charset) \ + ATLASSERT(bExTemplate); \ + wFontSize = pointsize; \ + szFontName = typeface; \ + wWeight = weight; \ + bItalic = italic; \ + bCharset = charset; +#define DIALOG_MENU(menuName) \ + Menu = menuName; +#define DIALOG_CLASS(className) \ + ClassName = className; + +#define BEGIN_CONTROLS_MAP() \ + void DoInitControls() \ + { + +#define END_CONTROLS_MAP() \ + }; + + +#define CONTROL_LTEXT(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_LEFT | WS_GROUP, exStyle, text, NULL, 0); +#define CONTROL_CTEXT(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_CENTER | WS_GROUP, exStyle, text, NULL, 0); +#define CONTROL_RTEXT(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_RIGHT | WS_GROUP, exStyle, text, NULL, 0); +#define CONTROL_PUSHBUTTON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_DEFPUSHBUTTON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_DEFPUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); +#ifndef _WIN32_WCE +#define CONTROL_PUSHBOX(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBOX | WS_TABSTOP, exStyle, text, NULL, 0); +#endif // !_WIN32_WCE +#define CONTROL_STATE3(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_3STATE | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_AUTO3STATE(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTO3STATE | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_CHECKBOX(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_CHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_AUTOCHECKBOX(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTOCHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_RADIOBUTTON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_RADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_AUTORADIOBUTTON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTORADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); +#define CONTROL_COMBOBOX(id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_COMBOBOX, (WORD)id, x, y, width, height, style | CBS_DROPDOWN | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0); +#define CONTROL_EDITTEXT(id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_EDIT, (WORD)id, x, y, width, height, style | ES_LEFT | WS_BORDER | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0); +#define CONTROL_GROUPBOX(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_GROUPBOX, exStyle, text, NULL, 0); +#define CONTROL_LISTBOX(id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_LISTBOX, (WORD)id, x, y, width, height, style | LBS_NOTIFY | WS_BORDER, exStyle, (LPCTSTR)NULL, NULL, 0); +#define CONTROL_SCROLLBAR(id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_SCROLLBAR, (WORD)id, x, y, width, height, style | SBS_HORZ, exStyle, (LPCTSTR)NULL, NULL, 0); +#define CONTROL_ICON(text, id, x, y, width, height, style, exStyle) \ + m_Template.AddStdControl(WTL::CMemDlgTemplate::CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_ICON, exStyle, text, NULL, 0); +#define CONTROL_CONTROL(text, id, className, style, x, y, width, height, exStyle) \ + m_Template.AddControl(className, (WORD)id, x, y, width, height, style, exStyle, text, NULL, 0); + + +/////////////////////////////////////////////////////////////////////////////// +// CIndirectDialogImpl - dialogs with template in memory + +template > +class ATL_NO_VTABLE CIndirectDialogImpl : public TBase +{ +public: + enum { IDD = 0 }; // no dialog template resource + + TDlgTemplate m_Template; + + void CreateTemplate() + { + T* pT = static_cast(this); + pT->DoInitTemplate(); + pT->DoInitControls(); + } + + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_hWnd == NULL); + + if (!m_Template.IsValid()) + CreateTemplate(); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL result = m_thunk.Init(NULL, NULL); + if (result == FALSE) + { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, pT); + +#ifdef _DEBUG + m_bModal = true; +#endif // _DEBUG + + return ::DialogBoxIndirectParam(ModuleHelper::GetResourceInstance(), m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam); + } + + HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL) + { + T* pT = static_cast(this); + ATLASSERT(pT->m_hWnd == NULL); + + if (!m_Template.IsValid()) + CreateTemplate(); + +#if (_ATL_VER >= 0x0800) + // Allocate the thunk structure here, where we can fail gracefully. + BOOL result = m_thunk.Init(NULL, NULL); + if (result == FALSE) + { + SetLastError(ERROR_OUTOFMEMORY); + return NULL; + } +#endif // (_ATL_VER >= 0x0800) + + ModuleHelper::AddCreateWndData(&m_thunk.cd, pT); + +#ifdef _DEBUG + m_bModal = false; +#endif // _DEBUG + + HWND hWnd = ::CreateDialogIndirectParam(ModuleHelper::GetResourceInstance(), (LPCDLGTEMPLATE)m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam); + ATLASSERT(m_hWnd == hWnd); + + return hWnd; + } + + // for CComControl + HWND Create(HWND hWndParent, RECT&, LPARAM dwInitParam = NULL) + { + return Create(hWndParent, dwInitParam); + } + + void DoInitTemplate() + { + ATLASSERT(FALSE); // MUST be defined in derived class + } + + void DoInitControls() + { + ATLASSERT(FALSE); // MUST be defined in derived class + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CPropertySheetWindow - client side for a property sheet + +class CPropertySheetWindow : public ATL::CWindow +{ +public: +// Constructors + CPropertySheetWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd) + { } + + CPropertySheetWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + int GetPageCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HWND hWndTabCtrl = GetTabControl(); + ATLASSERT(hWndTabCtrl != NULL); + return (int)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L); + } + + HWND GetActivePage() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L); + } + + int GetActiveIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + HWND hWndTabCtrl = GetTabControl(); + ATLASSERT(hWndTabCtrl != NULL); + return (int)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L); + } + + BOOL SetActivePage(int nPageIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, nPageIndex, 0L); + } + + BOOL SetActivePage(HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, 0, (LPARAM)hPage); + } + + BOOL SetActivePageByID(int nPageID) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSELID, 0, nPageID); + } + + void SetTitle(LPCTSTR lpszText, UINT nStyle = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid + ATLASSERT(lpszText != NULL); + ::SendMessage(m_hWnd, PSM_SETTITLE, nStyle, (LPARAM)lpszText); + } + + HWND GetTabControl() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L); + } + + void SetFinishText(LPCTSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText); + } + + void SetWizardButtons(DWORD dwFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags); + } + +// Operations + BOOL AddPage(HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage); + } + + BOOL AddPage(LPCPROPSHEETPAGE pPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pPage != NULL); + HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); + if(hPage == NULL) + return FALSE; + return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage); + } + +#ifndef _WIN32_WCE + BOOL InsertPage(int nNewPageIndex, HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage); + } + + BOOL InsertPage(int nNewPageIndex, LPCPROPSHEETPAGE pPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pPage != NULL); + HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); + if(hPage == NULL) + return FALSE; + return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage); + } + + BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage); + } + + BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, LPCPROPSHEETPAGE pPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pPage != NULL); + HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); + if(hPage == NULL) + return FALSE; + return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage); + } +#endif // !_WIN32_WCE + + void RemovePage(int nPageIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_REMOVEPAGE, nPageIndex, 0L); + } + + void RemovePage(HPROPSHEETPAGE hPage) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(hPage != NULL); + ::SendMessage(m_hWnd, PSM_REMOVEPAGE, 0, (LPARAM)hPage); + } + + BOOL PressButton(int nButton) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L); + } + + BOOL Apply() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_APPLY, 0, 0L); + } + + void CancelToClose() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_CANCELTOCLOSE, 0, 0L); + } + + void SetModified(HWND hWndPage, BOOL bChanged = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(::IsWindow(hWndPage)); + UINT uMsg = bChanged ? PSM_CHANGED : PSM_UNCHANGED; + ::SendMessage(m_hWnd, uMsg, (WPARAM)hWndPage, 0L); + } + + LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + return ::SendMessage(m_hWnd, PSM_QUERYSIBLINGS, wParam, lParam); + } + + void RebootSystem() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_REBOOTSYSTEM, 0, 0L); + } + + void RestartWindows() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_RESTARTWINDOWS, 0, 0L); + } + + BOOL IsDialogMessage(LPMSG lpMsg) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_ISDIALOGMESSAGE, 0, (LPARAM)lpMsg); + } + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + int HwndToIndex(HWND hWnd) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_HWNDTOINDEX, (WPARAM)hWnd, 0L); + } + + HWND IndexToHwnd(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, PSM_INDEXTOHWND, nIndex, 0L); + } + + int PageToIndex(HPROPSHEETPAGE hPage) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_PAGETOINDEX, 0, (LPARAM)hPage); + } + + HPROPSHEETPAGE IndexToPage(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HPROPSHEETPAGE)::SendMessage(m_hWnd, PSM_INDEXTOPAGE, nIndex, 0L); + } + + int IdToIndex(int nID) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_IDTOINDEX, 0, nID); + } + + int IndexToId(int nIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_INDEXTOID, nIndex, 0L); + } + + int GetResult() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, PSM_GETRESULT, 0, 0L); + } + + BOOL RecalcPageSizes() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, PSM_RECALCPAGESIZES, 0, 0L); + } + + void SetHeaderTitle(int nIndex, LPCTSTR lpstrHeaderTitle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETHEADERTITLE, nIndex, (LPARAM)lpstrHeaderTitle); + } + + void SetHeaderSubTitle(int nIndex, LPCTSTR lpstrHeaderSubTitle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETHEADERSUBTITLE, nIndex, (LPARAM)lpstrHeaderSubTitle); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Implementation - override to prevent usage + HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) + { + ATLASSERT(FALSE); + return NULL; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CPropertySheetImpl - implements a property sheet + +template +class ATL_NO_VTABLE CPropertySheetImpl : public ATL::CWindowImplBaseT< TBase > +{ +public: + PROPSHEETHEADER m_psh; + ATL::CSimpleArray m_arrPages; + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific + #ifndef PROPSHEET_LINK_SIZE + #define PROPSHEET_LINK_SIZE 128 + #endif // PROPSHEET_LINK_SIZE + TCHAR m_szLink[PROPSHEET_LINK_SIZE]; + static LPCTSTR m_pszTitle; + static LPCTSTR m_pszLink; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + +// Construction/Destruction + CPropertySheetImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) + { + memset(&m_psh, 0, sizeof(PROPSHEETHEADER)); + m_psh.dwSize = sizeof(PROPSHEETHEADER); + m_psh.dwFlags = PSH_USECALLBACK; + m_psh.hInstance = ModuleHelper::GetResourceInstance(); + m_psh.phpage = NULL; // will be set later + m_psh.nPages = 0; // will be set later + m_psh.pszCaption = title.m_lpstr; + m_psh.nStartPage = uStartPage; + m_psh.hwndParent = hWndParent; // if NULL, will be set in DoModal/Create + m_psh.pfnCallback = T::PropSheetCallback; + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific + m_psh.dwFlags |= PSH_MAXIMIZE; + m_szLink[0] = 0; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + } + + ~CPropertySheetImpl() + { + if(m_arrPages.GetSize() > 0) // sheet never created, destroy all pages + { + for(int i = 0; i < m_arrPages.GetSize(); i++) + ::DestroyPropertySheetPage((HPROPSHEETPAGE)m_arrPages[i]); + } + } + +// Callback function and overrideables + static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam) + { + lParam; // avoid level 4 warning + int nRet = 0; + + if(uMsg == PSCB_INITIALIZED) + { + ATLASSERT(hWnd != NULL); + T* pT = (T*)ModuleHelper::ExtractCreateWndData(); + // subclass the sheet window + pT->SubclassWindow(hWnd); + // remove page handles array + pT->_CleanUpPages(); + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific + m_pszTitle = pT->m_psh.pszCaption; + if(*pT->m_szLink != 0) + m_pszLink = pT->m_szLink; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific + + pT->OnSheetInitialized(); + } +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific uMsg + else + { + switch(uMsg) + { + case PSCB_GETVERSION : + nRet = COMCTL32_VERSION; + break; + case PSCB_GETTITLE : + if(m_pszTitle != NULL) + { + lstrcpy((LPTSTR)lParam, m_pszTitle); + m_pszTitle = NULL; + } + break; + case PSCB_GETLINKTEXT: + if(m_pszLink != NULL) + { + lstrcpy((LPTSTR)lParam, m_pszLink); + m_pszLink = NULL; + } + break; + default: + break; + } + } +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + + return nRet; + } + + void OnSheetInitialized() + { + } + +// Create method + HWND Create(HWND hWndParent = NULL) + { + ATLASSERT(m_hWnd == NULL); + + m_psh.dwFlags |= PSH_MODELESS; + if(m_psh.hwndParent == NULL) + m_psh.hwndParent = hWndParent; + m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData(); + m_psh.nPages = m_arrPages.GetSize(); + + T* pT = static_cast(this); + ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT); + + HWND hWnd = (HWND)::PropertySheet(&m_psh); + _CleanUpPages(); // ensure clean-up, required if call failed + + ATLASSERT(m_hWnd == hWnd); + + return hWnd; + } + + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) + { + ATLASSERT(m_hWnd == NULL); + + m_psh.dwFlags &= ~PSH_MODELESS; + if(m_psh.hwndParent == NULL) + m_psh.hwndParent = hWndParent; + m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData(); + m_psh.nPages = m_arrPages.GetSize(); + + T* pT = static_cast(this); + ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT); + + INT_PTR nRet = ::PropertySheet(&m_psh); + _CleanUpPages(); // ensure clean-up, required if call failed + + return nRet; + } + + // implementation helper - clean up pages array + void _CleanUpPages() + { + m_psh.nPages = 0; + m_psh.phpage = NULL; + m_arrPages.RemoveAll(); + } + +// Attributes (extended overrides of client class methods) +// These now can be called before the sheet is created +// Note: Calling these after the sheet is created gives unpredictable results + int GetPageCount() const + { + if(m_hWnd == NULL) // not created yet + return m_arrPages.GetSize(); + return TBase::GetPageCount(); + } + + int GetActiveIndex() const + { + if(m_hWnd == NULL) // not created yet + return m_psh.nStartPage; + return TBase::GetActiveIndex(); + } + + HPROPSHEETPAGE GetPage(int nPageIndex) const + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + return (HPROPSHEETPAGE)m_arrPages[nPageIndex]; + } + + int GetPageIndex(HPROPSHEETPAGE hPage) const + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + return m_arrPages.Find((HPROPSHEETPAGE&)hPage); + } + + BOOL SetActivePage(int nPageIndex) + { + if(m_hWnd == NULL) // not created yet + { + ATLASSERT(nPageIndex >= 0 && nPageIndex < m_arrPages.GetSize()); + m_psh.nStartPage = nPageIndex; + return TRUE; + } + return TBase::SetActivePage(nPageIndex); + } + + BOOL SetActivePage(HPROPSHEETPAGE hPage) + { + ATLASSERT(hPage != NULL); + if (m_hWnd == NULL) // not created yet + { + int nPageIndex = GetPageIndex(hPage); + if(nPageIndex == -1) + return FALSE; + + return SetActivePage(nPageIndex); + } + return TBase::SetActivePage(hPage); + + } + + void SetTitle(LPCTSTR lpszText, UINT nStyle = 0) + { + ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid + ATLASSERT(lpszText != NULL); + + if(m_hWnd == NULL) + { + // set internal state + m_psh.pszCaption = lpszText; // must exist until sheet is created + m_psh.dwFlags &= ~PSH_PROPTITLE; + m_psh.dwFlags |= nStyle; + } + else + { + // set external state + TBase::SetTitle(lpszText, nStyle); + } + } + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific Link field + void SetLinkText(LPCTSTR lpszText) + { + ATLASSERT(lpszText != NULL); + ATLASSERT(lstrlen(lpszText) < PROPSHEET_LINK_SIZE); + lstrcpy(m_szLink, lpszText); + } +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + + void SetWizardMode() + { + m_psh.dwFlags |= PSH_WIZARD; + } + + void EnableHelp() + { + m_psh.dwFlags |= PSH_HASHELP; + } + +// Operations + BOOL AddPage(HPROPSHEETPAGE hPage) + { + ATLASSERT(hPage != NULL); + BOOL bRet = FALSE; + if(m_hWnd != NULL) + bRet = TBase::AddPage(hPage); + else // sheet not created yet, use internal data + bRet = m_arrPages.Add((HPROPSHEETPAGE&)hPage); + return bRet; + } + + BOOL AddPage(LPCPROPSHEETPAGE pPage) + { + ATLASSERT(pPage != NULL); + HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); + if(hPage == NULL) + return FALSE; + BOOL bRet = AddPage(hPage); + if(!bRet) + ::DestroyPropertySheetPage(hPage); + return bRet; + } + + BOOL RemovePage(HPROPSHEETPAGE hPage) + { + ATLASSERT(hPage != NULL); + if (m_hWnd == NULL) // not created yet + { + int nPage = GetPageIndex(hPage); + if(nPage == -1) + return FALSE; + return RemovePage(nPage); + } + TBase::RemovePage(hPage); + return TRUE; + + } + + BOOL RemovePage(int nPageIndex) + { + BOOL bRet = TRUE; + if(m_hWnd != NULL) + TBase::RemovePage(nPageIndex); + else // sheet not created yet, use internal data + bRet = m_arrPages.RemoveAt(nPageIndex); + return bRet; + } + +#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + void SetHeader(LPCTSTR szbmHeader) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + + m_psh.dwFlags &= ~PSH_WIZARD; + m_psh.dwFlags |= (PSH_HEADER | PSH_WIZARD97); + m_psh.pszbmHeader = szbmHeader; + } + + void SetHeader(HBITMAP hbmHeader) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + + m_psh.dwFlags &= ~PSH_WIZARD; + m_psh.dwFlags |= (PSH_HEADER | PSH_USEHBMHEADER | PSH_WIZARD97); + m_psh.hbmHeader = hbmHeader; + } + + void SetWatermark(LPCTSTR szbmWatermark, HPALETTE hplWatermark = NULL) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + + m_psh.dwFlags &= ~PSH_WIZARD; + m_psh.dwFlags |= PSH_WATERMARK | PSH_WIZARD97; + m_psh.pszbmWatermark = szbmWatermark; + + if (hplWatermark != NULL) + { + m_psh.dwFlags |= PSH_USEHPLWATERMARK; + m_psh.hplWatermark = hplWatermark; + } + } + + void SetWatermark(HBITMAP hbmWatermark, HPALETTE hplWatermark = NULL) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + + m_psh.dwFlags &= ~PSH_WIZARD; + m_psh.dwFlags |= (PSH_WATERMARK | PSH_USEHBMWATERMARK | PSH_WIZARD97); + m_psh.hbmWatermark = hbmWatermark; + + if (hplWatermark != NULL) + { + m_psh.dwFlags |= PSH_USEHPLWATERMARK; + m_psh.hplWatermark = hplWatermark; + } + } + + void StretchWatermark(bool bStretchWatermark) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + if (bStretchWatermark) + m_psh.dwFlags |= PSH_STRETCHWATERMARK; + else + m_psh.dwFlags &= ~PSH_STRETCHWATERMARK; + } +#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +// Message map and handlers + BEGIN_MSG_MAP(CPropertySheetImpl) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) + END_MSG_MAP() + + LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); + if(HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) && + ((m_psh.dwFlags & PSH_MODELESS) != 0) && (GetActivePage() == NULL)) + DestroyWindow(); + return lRet; + } + + LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(((m_psh.dwFlags & PSH_MODELESS) == PSH_MODELESS) && ((wParam & 0xFFF0) == SC_CLOSE)) + SendMessage(WM_CLOSE); + else + bHandled = FALSE; + return 0; + } +}; + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC static pointers +template < class T, class TBase > +LPCWSTR CPropertySheetImpl::m_pszTitle = NULL; +template < class T, class TBase> +LPCWSTR CPropertySheetImpl::m_pszLink = NULL; +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + +// for non-customized sheets +class CPropertySheet : public CPropertySheetImpl +{ +public: + CPropertySheet(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) + : CPropertySheetImpl(title, uStartPage, hWndParent) + { } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPropertyPageWindow - client side for a property page + +class CPropertyPageWindow : public ATL::CWindow +{ +public: +// Constructors + CPropertyPageWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd) + { } + + CPropertyPageWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + CPropertySheetWindow GetPropertySheet() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CPropertySheetWindow(GetParent()); + } + +// Operations + BOOL Apply() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + return GetPropertySheet().Apply(); + } + + void CancelToClose() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().CancelToClose(); + } + + void SetModified(BOOL bChanged = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().SetModified(m_hWnd, bChanged); + } + + LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + return GetPropertySheet().QuerySiblings(wParam, lParam); + } + + void RebootSystem() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().RebootSystem(); + } + + void RestartWindows() + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().RestartWindows(); + } + + void SetWizardButtons(DWORD dwFlags) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetPropertySheet().SetWizardButtons(dwFlags); + } + +// Implementation - overrides to prevent usage + HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) + { + ATLASSERT(FALSE); + return NULL; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CPropertyPageImpl - implements a property page + +template +class ATL_NO_VTABLE CPropertyPageImpl : public ATL::CDialogImplBaseT< TBase > +{ +public: + PROPSHEETPAGE m_psp; + + operator PROPSHEETPAGE*() { return &m_psp; } + +// Construction + CPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) + { + // initialize PROPSHEETPAGE struct + memset(&m_psp, 0, sizeof(PROPSHEETPAGE)); + m_psp.dwSize = sizeof(PROPSHEETPAGE); + m_psp.dwFlags = PSP_USECALLBACK; + m_psp.hInstance = ModuleHelper::GetResourceInstance(); + T* pT = static_cast(this); + m_psp.pszTemplate = MAKEINTRESOURCE(pT->IDD); + m_psp.pfnDlgProc = (DLGPROC)T::StartDialogProc; + m_psp.pfnCallback = T::PropPageCallback; + m_psp.lParam = (LPARAM)pT; + + if(title.m_lpstr != NULL) + SetTitle(title); + } + +// Callback function and overrideables + static UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp) + { + hWnd; // avoid level 4 warning + ATLASSERT(hWnd == NULL); + T* pT = (T*)ppsp->lParam; + UINT uRet = 0; + + switch(uMsg) + { + case PSPCB_CREATE: + { + ATL::CDialogImplBaseT< TBase >* pPage = (ATL::CDialogImplBaseT< TBase >*)pT; + ModuleHelper::AddCreateWndData(&pPage->m_thunk.cd, pPage); + uRet = pT->OnPageCreate() ? 1 : 0; + } + break; +#if (_WIN32_IE >= 0x0500) + case PSPCB_ADDREF: + pT->OnPageAddRef(); + break; +#endif // (_WIN32_IE >= 0x0500) + case PSPCB_RELEASE: + pT->OnPageRelease(); + break; + default: + break; + } + + return uRet; + } + + bool OnPageCreate() + { + return true; // true - allow page to be created, false - prevent creation + } + +#if (_WIN32_IE >= 0x0500) + void OnPageAddRef() + { + } +#endif // (_WIN32_IE >= 0x0500) + + void OnPageRelease() + { + } + +// Create method + HPROPSHEETPAGE Create() + { + return ::CreatePropertySheetPage(&m_psp); + } + +// Attributes + void SetTitle(ATL::_U_STRINGorID title) + { + m_psp.pszTitle = title.m_lpstr; + m_psp.dwFlags |= PSP_USETITLE; + } + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + void SetHeaderTitle(LPCTSTR lpstrHeaderTitle) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psp.dwFlags |= PSP_USEHEADERTITLE; + m_psp.pszHeaderTitle = lpstrHeaderTitle; + } + + void SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle) + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psp.dwFlags |= PSP_USEHEADERSUBTITLE; + m_psp.pszHeaderSubTitle = lpstrHeaderSubTitle; + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Operations + void EnableHelp() + { + m_psp.dwFlags |= PSP_HASHELP; + } + +// Message map and handlers + BEGIN_MSG_MAP(CPropertyPageImpl) + MESSAGE_HANDLER(WM_NOTIFY, OnNotify) + END_MSG_MAP() + + // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification + // handlers that return direct values without any restrictions + LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { +#ifndef _WIN32_WCE + // This notification is sometimes received on Windows CE after the window is already destroyed + ATLASSERT(::IsWindow(m_hWnd)); +#endif + NMHDR* pNMHDR = (NMHDR*)lParam; + + // don't handle messages not from the page/sheet itself + if(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd)) + { + bHandled = FALSE; + return 1; + } +#ifdef _WIN32_WCE + ATLASSERT(::IsWindow(m_hWnd)); +#endif + + T* pT = static_cast(this); + LRESULT lResult = 0; + switch(pNMHDR->code) + { +#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS + case PSN_SETACTIVE: + lResult = pT->OnSetActive(); + break; + case PSN_KILLACTIVE: + lResult = pT->OnKillActive(); + break; + case PSN_APPLY: + lResult = pT->OnApply(); + break; + case PSN_RESET: + pT->OnReset(); + break; + case PSN_QUERYCANCEL: + lResult = pT->OnQueryCancel(); + break; + case PSN_WIZNEXT: + lResult = pT->OnWizardNext(); + break; + case PSN_WIZBACK: + lResult = pT->OnWizardBack(); + break; + case PSN_WIZFINISH: + lResult = pT->OnWizardFinish(); + break; + case PSN_HELP: + pT->OnHelp(); + break; +#ifndef _WIN32_WCE +#if (_WIN32_IE >= 0x0400) + case PSN_GETOBJECT: + if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam)) + bHandled = FALSE; + break; +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + case PSN_TRANSLATEACCELERATOR: + { + LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; + lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam); + } + break; + case PSN_QUERYINITIALFOCUS: + { + LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; + lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam); + } + break; +#endif // (_WIN32_IE >= 0x0500) +#endif // !_WIN32_WCE + +#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS + case PSN_SETACTIVE: + lResult = pT->OnSetActive() ? 0 : -1; + break; + case PSN_KILLACTIVE: + lResult = !pT->OnKillActive(); + break; + case PSN_APPLY: + lResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE; + break; + case PSN_RESET: + pT->OnReset(); + break; + case PSN_QUERYCANCEL: + lResult = !pT->OnQueryCancel(); + break; + case PSN_WIZNEXT: + lResult = pT->OnWizardNext(); + break; + case PSN_WIZBACK: + lResult = pT->OnWizardBack(); + break; + case PSN_WIZFINISH: + lResult = !pT->OnWizardFinish(); + break; + case PSN_HELP: + pT->OnHelp(); + break; +#ifndef _WIN32_WCE +#if (_WIN32_IE >= 0x0400) + case PSN_GETOBJECT: + if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam)) + bHandled = FALSE; + break; +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + case PSN_TRANSLATEACCELERATOR: + { + LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; + lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR; + } + break; + case PSN_QUERYINITIALFOCUS: + { + LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; + lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam); + } + break; +#endif // (_WIN32_IE >= 0x0500) +#endif // !_WIN32_WCE + +#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS + default: + bHandled = FALSE; // not handled + } + + return lResult; + } + +// Overridables + // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification + // handlers that return direct values without any restrictions +#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS + int OnSetActive() + { + // 0 = allow activate + // -1 = go back that was active + // page ID = jump to page + return 0; + } + + BOOL OnKillActive() + { + // FALSE = allow deactivate + // TRUE = prevent deactivation + return FALSE; + } + + int OnApply() + { + // PSNRET_NOERROR = apply OK + // PSNRET_INVALID = apply not OK, return to this page + // PSNRET_INVALID_NOCHANGEPAGE = apply not OK, don't change focus + return PSNRET_NOERROR; + } + + void OnReset() + { + } + + BOOL OnQueryCancel() + { + // FALSE = allow cancel + // TRUE = prevent cancel + return FALSE; + } + + int OnWizardBack() + { + // 0 = goto previous page + // -1 = prevent page change + // >0 = jump to page by dlg ID + return 0; + } + + int OnWizardNext() + { + // 0 = goto next page + // -1 = prevent page change + // >0 = jump to page by dlg ID + return 0; + } + + INT_PTR OnWizardFinish() + { + // FALSE = allow finish + // TRUE = prevent finish + // HWND = prevent finish and set focus to HWND (CommCtrl 5.80 only) + return FALSE; + } + + void OnHelp() + { + } + +#ifndef _WIN32_WCE +#if (_WIN32_IE >= 0x0400) + BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/) + { + return FALSE; // not processed + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + int OnTranslateAccelerator(LPMSG /*lpMsg*/) + { + // PSNRET_NOERROR - message not handled + // PSNRET_MESSAGEHANDLED - message handled + return PSNRET_NOERROR; + } + + HWND OnQueryInitialFocus(HWND /*hWndFocus*/) + { + // NULL = set focus to default control + // HWND = set focus to HWND + return NULL; + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_WIN32_WCE + +#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS + BOOL OnSetActive() + { + return TRUE; + } + + BOOL OnKillActive() + { + return TRUE; + } + + BOOL OnApply() + { + return TRUE; + } + + void OnReset() + { + } + + BOOL OnQueryCancel() + { + return TRUE; // ok to cancel + } + + int OnWizardBack() + { + // 0 = goto previous page + // -1 = prevent page change + // >0 = jump to page by dlg ID + return 0; + } + + int OnWizardNext() + { + // 0 = goto next page + // -1 = prevent page change + // >0 = jump to page by dlg ID + return 0; + } + + BOOL OnWizardFinish() + { + return TRUE; + } + + void OnHelp() + { + } + +#ifndef _WIN32_WCE +#if (_WIN32_IE >= 0x0400) + BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/) + { + return FALSE; // not processed + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + BOOL OnTranslateAccelerator(LPMSG /*lpMsg*/) + { + return FALSE; // not translated + } + + HWND OnQueryInitialFocus(HWND /*hWndFocus*/) + { + return NULL; // default + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_WIN32_WCE + +#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS +}; + +// for non-customized pages +template +class CPropertyPage : public CPropertyPageImpl > +{ +public: + enum { IDD = t_wDlgTemplateID }; + + CPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl(title) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + +/////////////////////////////////////////////////////////////////////////////// +// CAxPropertyPageImpl - property page that hosts ActiveX controls + +#ifndef _ATL_NO_HOSTING + +// Note: You must #include to use these classes + +template +class ATL_NO_VTABLE CAxPropertyPageImpl : public CPropertyPageImpl< T, TBase > +{ +public: +// Data members + HGLOBAL m_hInitData; + HGLOBAL m_hDlgRes; + HGLOBAL m_hDlgResSplit; + +// Constructor/destructor + CAxPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : + CPropertyPageImpl< T, TBase >(title), + m_hInitData(NULL), m_hDlgRes(NULL), m_hDlgResSplit(NULL) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + + // initialize ActiveX hosting and modify dialog template + ATL::AtlAxWinInit(); + + HINSTANCE hInstance = ModuleHelper::GetResourceInstance(); + LPCTSTR lpTemplateName = MAKEINTRESOURCE(pT->IDD); + HRSRC hDlg = ::FindResource(hInstance, lpTemplateName, (LPTSTR)RT_DIALOG); + if(hDlg != NULL) + { + HRSRC hDlgInit = ::FindResource(hInstance, lpTemplateName, (LPTSTR)_ATL_RT_DLGINIT); + + BYTE* pInitData = NULL; + if(hDlgInit != NULL) + { + m_hInitData = ::LoadResource(hInstance, hDlgInit); + pInitData = (BYTE*)::LockResource(m_hInitData); + } + + m_hDlgRes = ::LoadResource(hInstance, hDlg); + DLGTEMPLATE* pDlg = (DLGTEMPLATE*)::LockResource(m_hDlgRes); + LPCDLGTEMPLATE lpDialogTemplate = ATL::_DialogSplitHelper::SplitDialogTemplate(pDlg, pInitData); + if(lpDialogTemplate != pDlg) + m_hDlgResSplit = GlobalHandle(lpDialogTemplate); + + // set up property page to use in-memory dialog template + if(lpDialogTemplate != NULL) + { + m_psp.dwFlags |= PSP_DLGINDIRECT; + m_psp.pResource = lpDialogTemplate; + } + else + { + ATLASSERT(FALSE && _T("CAxPropertyPageImpl - ActiveX initializtion failed!")); + } + } + else + { + ATLASSERT(FALSE && _T("CAxPropertyPageImpl - Cannot find dialog template!")); + } + } + + ~CAxPropertyPageImpl() + { + if(m_hInitData != NULL) + { + UnlockResource(m_hInitData); + FreeResource(m_hInitData); + } + if(m_hDlgRes != NULL) + { + UnlockResource(m_hDlgRes); + FreeResource(m_hDlgRes); + } + if(m_hDlgResSplit != NULL) + { + ::GlobalFree(m_hDlgResSplit); + } + } + +// Methods + // call this one to handle keyboard message for ActiveX controls + BOOL PreTranslateMessage(LPMSG pMsg) + { + if ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) && + (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST)) + return FALSE; + // find a direct child of the dialog from the window that has focus + HWND hWndCtl = ::GetFocus(); + if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd) + { + do + { + hWndCtl = ::GetParent(hWndCtl); + } + while (::GetParent(hWndCtl) != m_hWnd); + } + // give controls a chance to translate this message + return (BOOL)::SendMessage(hWndCtl, WM_FORWARDMSG, 0, (LPARAM)pMsg); + } + +// Overridables +#if (_WIN32_IE >= 0x0500) + // new default implementation for ActiveX hosting pages +#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS + int OnTranslateAccelerator(LPMSG lpMsg) + { + T* pT = static_cast(this); + return (pT->PreTranslateMessage(lpMsg) != FALSE) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR; + } +#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS + BOOL OnTranslateAccelerator(LPMSG lpMsg) + { + T* pT = static_cast(this); + return pT->PreTranslateMessage(lpMsg); + } +#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS +#endif // (_WIN32_IE >= 0x0500) + +// Support for new stuff in ATL7 +#if (_ATL_VER >= 0x0700) + int GetIDD() + { + return( static_cast(this)->IDD ); + } + + virtual DLGPROC GetDialogProc() + { + return DialogProc; + } + + static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + CAxPropertyPageImpl< T, TBase >* pThis = (CAxPropertyPageImpl< T, TBase >*)hWnd; + if (uMsg == WM_INITDIALOG) + { + HRESULT hr; + if (FAILED(hr = pThis->CreateActiveXControls(pThis->GetIDD()))) + { + ATLASSERT(FALSE); + return FALSE; + } + } + return CPropertyPageImpl< T, TBase >::DialogProc(hWnd, uMsg, wParam, lParam); + } + +// ActiveX controls creation + virtual HRESULT CreateActiveXControls(UINT nID) + { + // Load dialog template and InitData + HRSRC hDlgInit = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)_ATL_RT_DLGINIT); + BYTE* pInitData = NULL; + HGLOBAL hData = NULL; + HRESULT hr = S_OK; + if (hDlgInit != NULL) + { + hData = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlgInit); + if (hData != NULL) + pInitData = (BYTE*) ::LockResource(hData); + } + + HRSRC hDlg = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)RT_DIALOG); + if (hDlg != NULL) + { + HGLOBAL hResource = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlg); + DLGTEMPLATE* pDlg = NULL; + if (hResource != NULL) + { + pDlg = (DLGTEMPLATE*) ::LockResource(hResource); + if (pDlg != NULL) + { + // Get first control on the template + BOOL bDialogEx = ATL::_DialogSplitHelper::IsDialogEx(pDlg); + WORD nItems = ATL::_DialogSplitHelper::DlgTemplateItemCount(pDlg); + + // Get first control on the dialog + DLGITEMTEMPLATE* pItem = ATL::_DialogSplitHelper::FindFirstDlgItem(pDlg); + HWND hWndPrev = GetWindow(GW_CHILD); + + // Create all ActiveX cotnrols in the dialog template and place them in the correct tab order (z-order) + for (WORD nItem = 0; nItem < nItems; nItem++) + { + DWORD wID = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : pItem->id; + if (ATL::_DialogSplitHelper::IsActiveXControl(pItem, bDialogEx)) + { + BYTE* pData = NULL; + DWORD dwLen = ATL::_DialogSplitHelper::FindCreateData(wID, pInitData, &pData); + ATL::CComPtr spStream; + if (dwLen != 0) + { + HGLOBAL h = GlobalAlloc(GHND, dwLen); + if (h != NULL) + { + BYTE* pBytes = (BYTE*) GlobalLock(h); + BYTE* pSource = pData; + SecureHelper::memcpy_x(pBytes, dwLen, pSource, dwLen); + GlobalUnlock(h); + CreateStreamOnHGlobal(h, TRUE, &spStream); + } + else + { + hr = E_OUTOFMEMORY; + break; + } + } + + ATL::CComBSTR bstrLicKey; + hr = ATL::_DialogSplitHelper::ParseInitData(spStream, &bstrLicKey.m_str); + if (SUCCEEDED(hr)) + { + ATL::CAxWindow2 wnd; + // Get control caption. + LPWSTR pszClassName = + bDialogEx ? + (LPWSTR)(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem) + 1) : + (LPWSTR)(pItem + 1); + // Get control rect. + RECT rect; + rect.left = + bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->x : + pItem->x; + rect.top = + bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->y : + pItem->y; + rect.right = rect.left + + (bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cx : + pItem->cx); + rect.bottom = rect.top + + (bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cy : + pItem->cy); + + // Convert from dialog units to screen units + MapDialogRect(&rect); + + // Create AxWindow with a NULL caption. + wnd.Create(m_hWnd, + &rect, + NULL, + (bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->style : + pItem->style) | WS_TABSTOP, + bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->exStyle : + 0, + bDialogEx ? + ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : + pItem->id, + NULL); + + if (wnd != NULL) + { +#ifndef _WIN32_WCE + // Set the Help ID + if (bDialogEx && ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID != 0) + wnd.SetWindowContextHelpId(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID); +#endif // !_WIN32_WCE + // Try to create the ActiveX control. + hr = wnd.CreateControlLic(pszClassName, spStream, NULL, bstrLicKey); + if (FAILED(hr)) + break; + // Set the correct tab position. + if (nItem == 0) + hWndPrev = HWND_TOP; + wnd.SetWindowPos(hWndPrev, 0,0,0,0,SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + hWndPrev = wnd; + } + else + { + hr = ATL::AtlHresultFromLastError(); + } + } + } + else + { + if (nItem != 0) + hWndPrev = ::GetWindow(hWndPrev, GW_HWNDNEXT); + } + pItem = ATL::_DialogSplitHelper::FindNextDlgItem(pItem, bDialogEx); + } + } + else + hr = ATL::AtlHresultFromLastError(); + } + else + hr = ATL::AtlHresultFromLastError(); + } + return hr; + } + +// Event handling support + HRESULT AdviseSinkMap(bool bAdvise) + { + if(!bAdvise && m_hWnd == NULL) + { + // window is gone, controls are already unadvised + ATLTRACE2(atlTraceUI, 0, _T("CAxPropertyPageImpl::AdviseSinkMap called after the window was destroyed\n")); + return S_OK; + } + HRESULT hRet = E_NOTIMPL; + __if_exists(T::_GetSinkMapFinder) + { + T* pT = static_cast(this); + hRet = AtlAdviseSinkMap(pT, bAdvise); + } + return hRet; + } + +// Message map and handlers + typedef CPropertyPageImpl< T, TBase> _baseClass; + BEGIN_MSG_MAP(CAxPropertyPageImpl) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + // initialize controls in dialog with DLGINIT resource section + ExecuteDlgInit(static_cast(this)->IDD); + AdviseSinkMap(true); + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + AdviseSinkMap(false); + bHandled = FALSE; + return 1; + } +#endif // (_ATL_VER >= 0x0700) +}; + +// for non-customized pages +template +class CAxPropertyPage : public CAxPropertyPageImpl > +{ +public: + enum { IDD = t_wDlgTemplateID }; + + CAxPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl(title) + { } + +#if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700) + // not empty so we handle accelerators/create controls + BEGIN_MSG_MAP(CAxPropertyPage) + CHAIN_MSG_MAP(CAxPropertyPageImpl >) + END_MSG_MAP() +#else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) + DECLARE_EMPTY_MSG_MAP() +#endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) +}; + +#endif // _ATL_NO_HOSTING + + +/////////////////////////////////////////////////////////////////////////////// +// Wizard97 Support + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Sample wizard dialog resources: +// +// IDD_WIZ97_INTERIOR_BLANK DIALOG 0, 0, 317, 143 +// STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION +// CAPTION "Wizard97 Property Page - Interior" +// FONT 8, "MS Shell Dlg" +// BEGIN +// END +// +// IDD_WIZ97_EXTERIOR_BLANK DIALOGEX 0, 0, 317, 193 +// STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +// CAPTION "Wizard97 Property Page - Welcome/Complete" +// FONT 8, "MS Shell Dlg", 0, 0, 0x0 +// BEGIN +// LTEXT "Welcome to the X Wizard",IDC_WIZ97_EXTERIOR_TITLE,115,8, +// 195,24 +// LTEXT "Wizard Explanation\r\n(The height of the static text should be in multiples of 8 dlus)", +// IDC_STATIC,115,40,195,16 +// LTEXT "h",IDC_WIZ97_BULLET1,118,64,8,8 +// LTEXT "List Item 1 (the h is turned into a bullet)",IDC_STATIC, +// 127,63,122,8 +// LTEXT "h",IDC_WIZ97_BULLET2,118,79,8,8 +// LTEXT "List Item 2. Keep 7 dlus between paragraphs",IDC_STATIC, +// 127,78,33,8 +// CONTROL "&Do not show this Welcome page again", +// IDC_WIZ97_WELCOME_NOTAGAIN,"Button",BS_AUTOCHECKBOX | +// WS_TABSTOP,115,169,138,10 +// END +// +// GUIDELINES DESIGNINFO +// BEGIN +// IDD_WIZ97_INTERIOR_BLANK, DIALOG +// BEGIN +// LEFTMARGIN, 7 +// RIGHTMARGIN, 310 +// VERTGUIDE, 21 +// VERTGUIDE, 31 +// VERTGUIDE, 286 +// VERTGUIDE, 296 +// TOPMARGIN, 7 +// BOTTOMMARGIN, 136 +// HORZGUIDE, 8 +// END +// +// IDD_WIZ97_EXTERIOR_BLANK, DIALOG +// BEGIN +// RIGHTMARGIN, 310 +// VERTGUIDE, 115 +// VERTGUIDE, 118 +// VERTGUIDE, 127 +// TOPMARGIN, 7 +// BOTTOMMARGIN, 186 +// HORZGUIDE, 8 +// HORZGUIDE, 32 +// HORZGUIDE, 40 +// HORZGUIDE, 169 +// END +// END + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97SheetWindow - client side for a Wizard 97 style wizard sheet + +class CWizard97SheetWindow : public CPropertySheetWindow +{ +public: +// Constructors + CWizard97SheetWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd) + { } + + CWizard97SheetWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Operations + HFONT GetExteriorPageTitleFont(void) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HFONT)::SendMessage(m_hWnd, GetMessage_GetExteriorPageTitleFont(), 0, 0L); + } + + HFONT GetBulletFont(void) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HFONT)::SendMessage(m_hWnd, GetMessage_GetBulletFont(), 0, 0L); + } + +// Helpers + static UINT GetMessage_GetExteriorPageTitleFont() + { + static UINT uGetExteriorPageTitleFont = 0; + if(uGetExteriorPageTitleFont == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont().\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uGetExteriorPageTitleFont == 0) + uGetExteriorPageTitleFont = ::RegisterWindowMessage(_T("GetExteriorPageTitleFont_531AF056-B8BE-4c4c-B786-AC608DF0DF12")); + + lock.Unlock(); + } + ATLASSERT(uGetExteriorPageTitleFont != 0); + return uGetExteriorPageTitleFont; + } + + static UINT GetMessage_GetBulletFont() + { + static UINT uGetBulletFont = 0; + if(uGetBulletFont == 0) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetBulletFont().\n")); + ATLASSERT(FALSE); + return 0; + } + + if(uGetBulletFont == 0) + uGetBulletFont = ::RegisterWindowMessage(_T("GetBulletFont_AD347D08-8F65-45ef-982E-6352E8218AD5")); + + lock.Unlock(); + } + ATLASSERT(uGetBulletFont != 0); + return uGetBulletFont; + } + +// Implementation - override to prevent usage + HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) + { + ATLASSERT(FALSE); + return NULL; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97SheetImpl - implements a Wizard 97 style wizard sheet + +template +class ATL_NO_VTABLE CWizard97SheetImpl : public CPropertySheetImpl< T, TBase > +{ +protected: +// Typedefs + typedef CWizard97SheetImpl< T, TBase > thisClass; + typedef CPropertySheetImpl< T, TBase > baseClass; + +// Member variables + CFont m_fontExteriorPageTitle; // Welcome and Completion page title font + CFont m_fontBullet; // Bullet font (used on static text 'h' to produce a small bullet) + bool m_bReceivedFirstSizeMessage; + +public: + CWizard97SheetImpl(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) : + baseClass(title, uStartPage, hWndParent), + m_bReceivedFirstSizeMessage(false) + { + m_psh.dwFlags &= ~(PSH_NOCONTEXTHELP); + m_psh.dwFlags &= ~(PSH_WIZARD | PSH_WIZARD_LITE); + + m_psh.dwFlags |= (PSH_HASHELP | PSH_WIZARDCONTEXTHELP); + m_psh.dwFlags |= PSH_WIZARD97; + + baseClass::SetHeader(headerBitmap.m_lpstr); + baseClass::SetWatermark(watermarkBitmap.m_lpstr); + } + +// Overrides from base class + void OnSheetInitialized() + { + T* pT = static_cast(this); + pT->_InitializeFonts(); + + // We'd like to center the wizard here, but its too early. + // Instead, we'll do CenterWindow upon our first WM_SIZE message + } + +// Initialization + void _InitializeFonts() + { + // Setup the Title and Bullet Font + // (Property pages can send the "get external page title font" and "get bullet font" messages) + // The derived class needs to do the actual SetFont for the dialog items) + + CFontHandle fontThisDialog = this->GetFont(); + CClientDC dcScreen(NULL); + + LOGFONT titleLogFont = {0}; + LOGFONT bulletLogFont = {0}; + fontThisDialog.GetLogFont(&titleLogFont); + fontThisDialog.GetLogFont(&bulletLogFont); + + // The Wizard 97 Spec recommends to do the Title Font + // as Verdana Bold, 12pt. + titleLogFont.lfCharSet = DEFAULT_CHARSET; + titleLogFont.lfWeight = FW_BOLD; + SecureHelper::strcpy_x(titleLogFont.lfFaceName, _countof(titleLogFont.lfFaceName), _T("Verdana Bold")); + INT titleFontPointSize = 12; + titleLogFont.lfHeight = -::MulDiv(titleFontPointSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72); + m_fontExteriorPageTitle.CreateFontIndirect(&titleLogFont); + + // The Wizard 97 Spec recommends to do Bullets by having + // static text of "h" in the Marlett font. + bulletLogFont.lfCharSet = DEFAULT_CHARSET; + bulletLogFont.lfWeight = FW_NORMAL; + SecureHelper::strcpy_x(bulletLogFont.lfFaceName, _countof(bulletLogFont.lfFaceName), _T("Marlett")); + INT bulletFontSize = 8; + bulletLogFont.lfHeight = -::MulDiv(bulletFontSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72); + m_fontBullet.CreateFontIndirect(&bulletLogFont); + } + +// Message Handling + BEGIN_MSG_MAP(thisClass) + MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont(), OnGetExteriorPageTitleFont) + MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetBulletFont(), OnGetBulletFont) + MESSAGE_HANDLER(WM_SIZE, OnSize) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() + + LRESULT OnGetExteriorPageTitleFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)(HFONT)m_fontExteriorPageTitle; + } + + LRESULT OnGetBulletFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return (LRESULT)(HFONT)m_fontBullet; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(!m_bReceivedFirstSizeMessage) + { + m_bReceivedFirstSizeMessage = true; + this->CenterWindow(); + } + + bHandled = FALSE; + return 0; + } +}; + +// for non-customized sheets +class CWizard97Sheet : public CWizard97SheetImpl +{ +protected: +// Typedefs + typedef CWizard97Sheet thisClass; + typedef CWizard97SheetImpl baseClass; + +public: + CWizard97Sheet(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) : + baseClass(title, headerBitmap, watermarkBitmap, uStartPage, hWndParent) + { } + + BEGIN_MSG_MAP(thisClass) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97PageWindow - client side for a Wizard 97 style wizard page + +#define WIZARD97_EXTERIOR_CXDLG 317 +#define WIZARD97_EXTERIOR_CYDLG 193 + +#define WIZARD97_INTERIOR_CXDLG 317 +#define WIZARD97_INTERIOR_CYDLG 143 + +class CWizard97PageWindow : public CPropertyPageWindow +{ +public: +// Constructors + CWizard97PageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd) + { } + + CWizard97PageWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + CWizard97SheetWindow GetPropertySheet() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return CWizard97SheetWindow(GetParent()); + } + +// Operations + HFONT GetExteriorPageTitleFont(void) + { + ATLASSERT(::IsWindow(m_hWnd)); + return GetPropertySheet().GetExteriorPageTitleFont(); + } + + HFONT GetBulletFont(void) + { + ATLASSERT(::IsWindow(m_hWnd)); + return GetPropertySheet().GetBulletFont(); + } + +// Implementation - overrides to prevent usage + HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) + { + ATLASSERT(FALSE); + return NULL; + } + +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97PageImpl - implements a Wizard 97 style wizard page + +template +class ATL_NO_VTABLE CWizard97PageImpl : public CPropertyPageImpl< T, TBase > +{ +protected: +// Typedefs + typedef CWizard97PageImpl< T, TBase > thisClass; + typedef CPropertyPageImpl< T, TBase > baseClass; + +public: + CWizard97PageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title) + { } + +// Message Handling + BEGIN_MSG_MAP(thisClass) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97ExteriorPageImpl - implements a Wizard 97 style exterior wizard page + +template +class ATL_NO_VTABLE CWizard97ExteriorPageImpl : public CPropertyPageImpl< T, TBase > +{ +protected: +// Typedefs + typedef CWizard97ExteriorPageImpl< T, TBase > thisClass; + typedef CPropertyPageImpl< T, TBase > baseClass; + +public: +// Constructors + CWizard97ExteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title) + { + m_psp.dwFlags |= PSP_HASHELP; + m_psp.dwFlags |= PSP_HIDEHEADER; + } + +// Message Handling + BEGIN_MSG_MAP(thisClass) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CWizard97InteriorPageImpl - implements a Wizard 97 style interior wizard page + +template +class ATL_NO_VTABLE CWizard97InteriorPageImpl : public CPropertyPageImpl< T, TBase > +{ +protected: +// Typedefs + typedef CWizard97InteriorPageImpl< T, TBase > thisClass; + typedef CPropertyPageImpl< T, TBase > baseClass; + +public: +// Constructors + CWizard97InteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title) + { + m_psp.dwFlags |= PSP_HASHELP; + m_psp.dwFlags &= ~PSP_HIDEHEADER; + m_psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; + + // Be sure to have the derived class define this in the constructor. + // We'll default it to something obvious in case its forgotten. + baseClass::SetHeaderTitle(_T("Call SetHeaderTitle in Derived Class")); + baseClass::SetHeaderSubTitle(_T("Call SetHeaderSubTitle in the constructor of the Derived Class.")); + } + +// Message Handling + BEGIN_MSG_MAP(thisClass) + CHAIN_MSG_MAP(baseClass) + END_MSG_MAP() +}; + +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// Aero Wizard support + +#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardFrameWindow - client side for an Aero Wizard frame window + +class CAeroWizardFrameWindow : public CPropertySheetWindow +{ +public: +// Constructors + CAeroWizardFrameWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd) + { } + + CAeroWizardFrameWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Operations - new, Aero Wizard only + void SetNextText(LPCWSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETNEXTTEXT, 0, (LPARAM)lpszText); + } + + void ShowWizardButtons(DWORD dwButtons, DWORD dwStates) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::PostMessage(m_hWnd, PSM_SHOWWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons); + } + + void EnableWizardButtons(DWORD dwButtons, DWORD dwStates) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::PostMessage(m_hWnd, PSM_ENABLEWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons); + } + + void SetButtonText(DWORD dwButton, LPCWSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, PSM_SETBUTTONTEXT, (WPARAM)dwButton, (LPARAM)lpszText); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardFrameImpl - implements an Aero Wizard frame + +template +class ATL_NO_VTABLE CAeroWizardFrameImpl : public CPropertySheetImpl +{ +public: +// Constructor + CAeroWizardFrameImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) : + CPropertySheetImpl(title, uStartPage, hWndParent) + { + m_psh.dwFlags |= PSH_WIZARD | PSH_AEROWIZARD; + } + +// Operations + void EnableResizing() + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psh.dwFlags |= PSH_RESIZABLE; + } + + void UseHeaderBitmap() + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psh.dwFlags |= PSH_HEADERBITMAP; + } + + void SetNoMargin() + { + ATLASSERT(m_hWnd == NULL); // can't do this after it's created + m_psh.dwFlags |= PSH_NOMARGIN; + } + +// Override to prevent use + HWND Create(HWND /*hWndParent*/ = NULL) + { + ATLASSERT(FALSE); // not supported for Aero Wizard + return NULL; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardFrame - for non-customized frames + +class CAeroWizardFrame : public CAeroWizardFrameImpl +{ +public: + CAeroWizardFrame(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) + : CAeroWizardFrameImpl(title, uStartPage, hWndParent) + { } + + BEGIN_MSG_MAP(CAeroWizardFrame) + MESSAGE_HANDLER(WM_COMMAND, CAeroWizardFrameImpl::OnCommand) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardPageWindow - client side for an Aero Wizard page + +class CAeroWizardPageWindow : public CPropertyPageWindow +{ +public: +// Constructors + CAeroWizardPageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd) + { } + + CAeroWizardPageWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Attributes + CAeroWizardFrameWindow GetAeroWizardFrame() const + { + ATLASSERT(::IsWindow(m_hWnd)); + // This is not really top-level frame window, but it processes all frame messages + return CAeroWizardFrameWindow(GetParent()); + } + +// Operations - new, Aero Wizard only + void SetNextText(LPCWSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetAeroWizardFrame().SetNextText(lpszText); + } + + void ShowWizardButtons(DWORD dwButtons, DWORD dwStates) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetAeroWizardFrame().ShowWizardButtons(dwButtons, dwStates); + } + + void EnableWizardButtons(DWORD dwButtons, DWORD dwStates) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetAeroWizardFrame().EnableWizardButtons(dwButtons, dwStates); + } + + void SetButtonText(DWORD dwButton, LPCWSTR lpszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + GetAeroWizardFrame().SetButtonText(dwButton, lpszText); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardPageImpl - implements an Aero Wizard page + +template +class ATL_NO_VTABLE CAeroWizardPageImpl : public CPropertyPageImpl +{ +public: + CAeroWizardPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl(title) + { } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardPage - for non-customized pages + +template +class CAeroWizardPage : public CAeroWizardPageImpl > +{ +public: + enum { IDD = t_wDlgTemplateID }; + + CAeroWizardPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardPageImpl(title) + { } + + DECLARE_EMPTY_MSG_MAP() +}; + + +#ifndef _ATL_NO_HOSTING + +// Note: You must #include to use these classes + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardAxPageImpl - Aero Wizard page that hosts ActiveX controls + +template +class ATL_NO_VTABLE CAeroWizardAxPageImpl : public CAxPropertyPageImpl< T, TBase > +{ +public: + CAeroWizardAxPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl< T, TBase >(title) + { } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAeroWizardAxPage - for non-customized pages + +template +class CAeroWizardAxPage : public CAeroWizardAxPageImpl > +{ +public: + enum { IDD = t_wDlgTemplateID }; + + CAeroWizardAxPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardAxPageImpl(title) + { } + +#if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700) + // not empty so we handle accelerators/create controls + BEGIN_MSG_MAP(CAeroWizardAxPage) + CHAIN_MSG_MAP(CAeroWizardAxPageImpl >) + END_MSG_MAP() +#else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) + DECLARE_EMPTY_MSG_MAP() +#endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) +}; + +#endif // _ATL_NO_HOSTING + +#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// TaskDialog support + +#if ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE) + +/////////////////////////////////////////////////////////////////////////////// +// AtlTaskDialog - support for TaskDialog() function + +inline int AtlTaskDialog(HWND hWndParent, + ATL::_U_STRINGorID WindowTitle, ATL::_U_STRINGorID MainInstructionText, ATL::_U_STRINGorID ContentText, + TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons = 0U, ATL::_U_STRINGorID Icon = (LPCTSTR)NULL) +{ + int nRet = -1; + +#ifdef _WTL_TASKDIALOG_DIRECT + USES_CONVERSION; + HRESULT hRet = ::TaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), T2CW(WindowTitle.m_lpstr), T2CW(MainInstructionText.m_lpstr), T2CW(ContentText.m_lpstr), dwCommonButtons, T2CW(Icon.m_lpstr), &nRet); + ATLVERIFY(SUCCEEDED(hRet)); +#else + // This allows apps to run on older versions of Windows + typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialog)(HWND hwndParent, HINSTANCE hInstance, PCWSTR pszWindowTitle, PCWSTR pszMainInstruction, PCWSTR pszContent, TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons, PCWSTR pszIcon, int* pnButton); + + HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll")); + if(m_hCommCtrlDLL != NULL) + { + PFN_TaskDialog pfnTaskDialog = (PFN_TaskDialog)::GetProcAddress(m_hCommCtrlDLL, "TaskDialog"); + if(pfnTaskDialog != NULL) + { + USES_CONVERSION; + HRESULT hRet = pfnTaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), T2CW(WindowTitle.m_lpstr), T2CW(MainInstructionText.m_lpstr), T2CW(ContentText.m_lpstr), dwCommonButtons, T2CW(Icon.m_lpstr), &nRet); + ATLVERIFY(SUCCEEDED(hRet)); + } + + ::FreeLibrary(m_hCommCtrlDLL); + } +#endif + + return nRet; +} + + +/////////////////////////////////////////////////////////////////////////////// +// CTaskDialogConfig - TASKDIALOGCONFIG wrapper + +class CTaskDialogConfig : public TASKDIALOGCONFIG +{ +public: +// Constructor + CTaskDialogConfig() + { + Init(); + } + + void Init() + { + memset(this, 0, sizeof(TASKDIALOGCONFIG)); // initialize structure to 0/NULL + this->cbSize = sizeof(TASKDIALOGCONFIG); + this->hInstance = ModuleHelper::GetResourceInstance(); + } + +// Operations - setting values + // common buttons + void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons) + { + this->dwCommonButtons = dwCommonButtons; + } + + // window title text + void SetWindowTitle(UINT nID) + { + this->pszWindowTitle = MAKEINTRESOURCEW(nID); + } + + void SetWindowTitle(LPCWSTR lpstrWindowTitle) + { + this->pszWindowTitle = lpstrWindowTitle; + } + + // main icon + void SetMainIcon(HICON hIcon) + { + this->dwFlags |= TDF_USE_HICON_MAIN; + this->hMainIcon = hIcon; + } + + void SetMainIcon(UINT nID) + { + this->dwFlags &= ~TDF_USE_HICON_MAIN; + this->pszMainIcon = MAKEINTRESOURCEW(nID); + } + + void SetMainIcon(LPCWSTR lpstrMainIcon) + { + this->dwFlags &= ~TDF_USE_HICON_MAIN; + this->pszMainIcon = lpstrMainIcon; + } + + // main instruction text + void SetMainInstructionText(UINT nID) + { + this->pszMainInstruction = MAKEINTRESOURCEW(nID); + } + + void SetMainInstructionText(LPCWSTR lpstrMainInstruction) + { + this->pszMainInstruction = lpstrMainInstruction; + } + + // content text + void SetContentText(UINT nID) + { + this->pszContent = MAKEINTRESOURCEW(nID); + } + + void SetContentText(LPCWSTR lpstrContent) + { + this->pszContent = lpstrContent; + } + + // buttons + void SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0) + { + this->pButtons = pButtons; + this->cButtons = cButtons; + if(nDefaultButton != 0) + this->nDefaultButton = nDefaultButton; + } + + void SetDefaultButton(int nDefaultButton) + { + this->nDefaultButton = nDefaultButton; + } + + // radio buttons + void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0) + { + this->pRadioButtons = pRadioButtons; + this->cRadioButtons = cRadioButtons; + if(nDefaultRadioButton != 0) + this->nDefaultRadioButton = nDefaultRadioButton; + } + + void SetDefaultRadioButton(int nDefaultRadioButton) + { + this->nDefaultRadioButton = nDefaultRadioButton; + } + + // verification text + void SetVerificationText(UINT nID) + { + this->pszVerificationText = MAKEINTRESOURCEW(nID); + } + + void SetVerificationText(LPCWSTR lpstrVerificationText) + { + this->pszVerificationText = lpstrVerificationText; + } + + // expanded information text + void SetExpandedInformationText(UINT nID) + { + this->pszExpandedInformation = MAKEINTRESOURCEW(nID); + } + + void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation) + { + this->pszExpandedInformation = lpstrExpandedInformation; + } + + // expanded control text + void SetExpandedControlText(UINT nID) + { + this->pszExpandedControlText = MAKEINTRESOURCEW(nID); + } + + void SetExpandedControlText(LPCWSTR lpstrExpandedControlText) + { + this->pszExpandedControlText = lpstrExpandedControlText; + } + + // collapsed control text + void SetCollapsedControlText(UINT nID) + { + this->pszCollapsedControlText = MAKEINTRESOURCEW(nID); + } + + void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText) + { + this->pszCollapsedControlText = lpstrCollapsedControlText; + } + + // footer icon + void SetFooterIcon(HICON hIcon) + { + this->dwFlags |= TDF_USE_HICON_FOOTER; + this->hFooterIcon = hIcon; + } + + void SetFooterIcon(UINT nID) + { + this->dwFlags &= ~TDF_USE_HICON_FOOTER; + this->pszFooterIcon = MAKEINTRESOURCEW(nID); + } + + void SetFooterIcon(LPCWSTR lpstrFooterIcon) + { + this->dwFlags &= ~TDF_USE_HICON_FOOTER; + this->pszFooterIcon = lpstrFooterIcon; + } + + // footer text + void SetFooterText(UINT nID) + { + this->pszFooter = MAKEINTRESOURCEW(nID); + } + + void SetFooterText(LPCWSTR lpstrFooterText) + { + this->pszFooter = lpstrFooterText; + } + + // width (in DLUs) + void SetWidth(UINT cxWidth) + { + this->cxWidth = cxWidth; + } + + // modify flags + void ModifyFlags(DWORD dwRemove, DWORD dwAdd) + { + this->dwFlags = (this->dwFlags & ~dwRemove) | dwAdd; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CTaskDialogImpl - implements a Task Dialog + +template +class ATL_NO_VTABLE CTaskDialogImpl +{ +public: + CTaskDialogConfig m_tdc; + HWND m_hWnd; // used only in callback functions + +// Constructor + CTaskDialogImpl(HWND hWndParent = NULL) : m_hWnd(NULL) + { + m_tdc.hwndParent = hWndParent; + m_tdc.pfCallback = T::TaskDialogCallback; + m_tdc.lpCallbackData = (LONG_PTR)static_cast(this); + } + +// Operations + HRESULT DoModal(HWND hWndParent = ::GetActiveWindow(), int* pnButton = NULL, int* pnRadioButton = NULL, BOOL* pfVerificationFlagChecked = NULL) + { + if(m_tdc.hwndParent == NULL) + m_tdc.hwndParent = hWndParent; + +#ifdef _WTL_TASKDIALOG_DIRECT + return ::TaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked); +#else + + // This allows apps to run on older versions of Windows + typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialogIndirect)(const TASKDIALOGCONFIG* pTaskConfig, int* pnButton, int* pnRadioButton, BOOL* pfVerificationFlagChecked); + + HRESULT hRet = E_UNEXPECTED; + HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll")); + if(m_hCommCtrlDLL != NULL) + { + PFN_TaskDialogIndirect pfnTaskDialogIndirect = (PFN_TaskDialogIndirect)::GetProcAddress(m_hCommCtrlDLL, "TaskDialogIndirect"); + if(pfnTaskDialogIndirect != NULL) + hRet = pfnTaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked); + + ::FreeLibrary(m_hCommCtrlDLL); + } + + return hRet; +#endif + } + +// Operations - setting values of TASKDIALOGCONFIG + // common buttons + void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons) + { m_tdc.SetCommonButtons(dwCommonButtons); } + // window title text + void SetWindowTitle(UINT nID) + { m_tdc.SetWindowTitle(nID); } + void SetWindowTitle(LPCWSTR lpstrWindowTitle) + { m_tdc.SetWindowTitle(lpstrWindowTitle); } + // main icon + void SetMainIcon(HICON hIcon) + { m_tdc.SetMainIcon(hIcon); } + void SetMainIcon(UINT nID) + { m_tdc.SetMainIcon(nID); } + void SetMainIcon(LPCWSTR lpstrMainIcon) + { m_tdc.SetMainIcon(lpstrMainIcon); } + // main instruction text + void SetMainInstructionText(UINT nID) + { m_tdc.SetMainInstructionText(nID); } + void SetMainInstructionText(LPCWSTR lpstrMainInstruction) + { m_tdc.SetMainInstructionText(lpstrMainInstruction); } + // content text + void SetContentText(UINT nID) + { m_tdc.SetContentText(nID); } + void SetContentText(LPCWSTR lpstrContent) + { m_tdc.SetContentText(lpstrContent); } + // buttons + void SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0) + { m_tdc.SetButtons(pButtons, cButtons, nDefaultButton); } + void SetDefaultButton(int nDefaultButton) + { m_tdc.SetDefaultButton(nDefaultButton); } + // radio buttons + void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0) + { m_tdc.SetRadioButtons(pRadioButtons, cRadioButtons, nDefaultRadioButton); } + void SetDefaultRadioButton(int nDefaultRadioButton) + { m_tdc.SetDefaultRadioButton(nDefaultRadioButton); } + // verification text + void SetVerificationText(UINT nID) + { m_tdc.SetVerificationText(nID); } + void SetVerificationText(LPCWSTR lpstrVerificationText) + { m_tdc.SetVerificationText(lpstrVerificationText); } + // expanded information text + void SetExpandedInformationText(UINT nID) + { m_tdc.SetExpandedInformationText(nID); } + void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation) + { m_tdc.SetExpandedInformationText(lpstrExpandedInformation); } + // expanded control text + void SetExpandedControlText(UINT nID) + { m_tdc.SetExpandedControlText(nID); } + void SetExpandedControlText(LPCWSTR lpstrExpandedControlText) + { m_tdc.SetExpandedControlText(lpstrExpandedControlText); } + // collapsed control text + void SetCollapsedControlText(UINT nID) + { m_tdc.SetCollapsedControlText(nID); } + void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText) + { m_tdc.SetCollapsedControlText(lpstrCollapsedControlText); } + // footer icon + void SetFooterIcon(HICON hIcon) + { m_tdc.SetFooterIcon(hIcon); } + void SetFooterIcon(UINT nID) + { m_tdc.SetFooterIcon(nID); } + void SetFooterIcon(LPCWSTR lpstrFooterIcon) + { m_tdc.SetFooterIcon(lpstrFooterIcon); } + // footer text + void SetFooterText(UINT nID) + { m_tdc.SetFooterText(nID); } + void SetFooterText(LPCWSTR lpstrFooterText) + { m_tdc.SetFooterText(lpstrFooterText); } + // width (in DLUs) + void SetWidth(UINT cxWidth) + { m_tdc.SetWidth(cxWidth); } + // modify flags + void ModifyFlags(DWORD dwRemove, DWORD dwAdd) + { m_tdc.ModifyFlags(dwRemove, dwAdd); } + +// Implementation + static HRESULT CALLBACK TaskDialogCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData) + { + T* pT = (T*)lpRefData; + ATLASSERT(pT->m_hWnd == NULL || pT->m_hWnd == hWnd); + + BOOL bRet = FALSE; + switch(uMsg) + { + case TDN_DIALOG_CONSTRUCTED: + pT->m_hWnd = hWnd; + pT->OnDialogConstructed(); + break; + case TDN_CREATED: + pT->OnCreated(); + break; + case TDN_BUTTON_CLICKED: + bRet = pT->OnButtonClicked((int)wParam); + break; + case TDN_RADIO_BUTTON_CLICKED: + pT->OnRadioButtonClicked((int)wParam); + break; + case TDN_HYPERLINK_CLICKED: + pT->OnHyperlinkClicked((LPCWSTR)lParam); + break; + case TDN_EXPANDO_BUTTON_CLICKED: + pT->OnExpandoButtonClicked((wParam != 0)); + break; + case TDN_VERIFICATION_CLICKED: + pT->OnVerificationClicked((wParam != 0)); + break; + case TDN_HELP: + pT->OnHelp(); + break; + case TDN_TIMER: + bRet = pT->OnTimer((DWORD)wParam); + break; + case TDN_NAVIGATED: + pT->OnNavigated(); + break; + case TDN_DESTROYED: + pT->OnDestroyed(); + pT->m_hWnd = NULL; + break; + default: + ATLTRACE2(atlTraceUI, 0, _T("Unknown notification received in CTaskDialogImpl::TaskDialogCallback\n")); + break; + } + + return (HRESULT)bRet; + } + +// Overrideables - notification handlers + void OnDialogConstructed() + { + } + + void OnCreated() + { + } + + BOOL OnButtonClicked(int /*nButton*/) + { + return FALSE; // don't prevent dialog to close + } + + void OnRadioButtonClicked(int /*nRadioButton*/) + { + } + + void OnHyperlinkClicked(LPCWSTR /*pszHREF*/) + { + } + + void OnExpandoButtonClicked(bool /*bExpanded*/) + { + } + + void OnVerificationClicked(bool /*bChecked*/) + { + } + + void OnHelp() + { + } + + BOOL OnTimer(DWORD /*dwTickCount*/) + { + return FALSE; // don't reset counter + } + + void OnNavigated() + { + } + + void OnDestroyed() + { + } + +// Commands - valid to call only from handlers + void NavigatePage(TASKDIALOGCONFIG& tdc) + { + ATLASSERT(m_hWnd != NULL); + + tdc.cbSize = sizeof(TASKDIALOGCONFIG); + if(tdc.hwndParent == NULL) + tdc.hwndParent = m_tdc.hwndParent; + tdc.pfCallback = m_tdc.pfCallback; + tdc.lpCallbackData = m_tdc.lpCallbackData; + (TASKDIALOGCONFIG)m_tdc = tdc; + + ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&tdc); + } + + // modify TASKDIALOGCONFIG values, then call this to update task dialog + void NavigatePage() + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&m_tdc); + } + + void ClickButton(int nButton) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_CLICK_BUTTON, nButton, 0L); + } + + void SetMarqueeProgressBar(BOOL bMarquee) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_SET_MARQUEE_PROGRESS_BAR, bMarquee, 0L); + } + + BOOL SetProgressBarState(int nNewState) + { + ATLASSERT(m_hWnd != NULL); + return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_STATE, nNewState, 0L); + } + + DWORD SetProgressBarRange(int nMinRange, int nMaxRange) + { + ATLASSERT(m_hWnd != NULL); + return (DWORD)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(nMinRange, nMaxRange)); + } + + int SetProgressBarPos(int nNewPos) + { + ATLASSERT(m_hWnd != NULL); + return (int)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_POS, nNewPos, 0L); + } + + BOOL SetProgressBarMarquee(BOOL bMarquee, UINT uSpeed) + { + ATLASSERT(m_hWnd != NULL); + return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_MARQUEE, bMarquee, uSpeed); + } + + void SetElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_SET_ELEMENT_TEXT, element, (LPARAM)lpstrText); + } + + void ClickRadioButton(int nRadioButton) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_CLICK_RADIO_BUTTON, nRadioButton, 0L); + } + + void EnableButton(int nButton, BOOL bEnable) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_ENABLE_BUTTON, nButton, bEnable); + } + + void EnableRadioButton(int nButton, BOOL bEnable) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_ENABLE_RADIO_BUTTON, nButton, bEnable); + } + + void ClickVerification(BOOL bCheck, BOOL bFocus) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_CLICK_VERIFICATION, bCheck, bFocus); + } + + void UpdateElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_UPDATE_ELEMENT_TEXT, element, (LPARAM)lpstrText); + } + + void SetButtonElevationRequiredState(int nButton, BOOL bElevation) + { + ATLASSERT(m_hWnd != NULL); + ::SendMessage(m_hWnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, nButton, bElevation); + } + + void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, HICON hIcon) + { + ATLASSERT(m_hWnd != NULL); +#ifdef _DEBUG + if(element == TDIE_ICON_MAIN) + ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) != 0); + else if(element == TDIE_ICON_FOOTER) + ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) != 0); +#endif // _DEBUG + ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)hIcon); + } + + void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, LPCWSTR lpstrIcon) + { + ATLASSERT(m_hWnd != NULL); +#ifdef _DEBUG + if(element == TDIE_ICON_MAIN) + ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) == 0); + else if(element == TDIE_ICON_FOOTER) + ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) == 0); +#endif // _DEBUG + ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)lpstrIcon); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CTaskDialog - for non-customized task dialogs + +class CTaskDialog : public CTaskDialogImpl +{ +public: + CTaskDialog(HWND hWndParent = NULL) : CTaskDialogImpl(hWndParent) + { + m_tdc.pfCallback = NULL; + } +}; + +#endif // ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE) + +}; // namespace WTL + +#endif // __ATLDLGS_H__ diff --git a/wtl/wtl/include/atlfind.h b/wtl/wtl/include/atlfind.h new file mode 100644 index 00000000..a1dd52db --- /dev/null +++ b/wtl/wtl/include/atlfind.h @@ -0,0 +1,1036 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLFIND_H__ +#define __ATLFIND_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifdef _WIN32_WCE + #error atlfind.h is not supported on Windows CE +#endif + +#ifndef __ATLCTRLS_H__ + #error atlfind.h requires atlctrls.h to be included first +#endif + +#ifndef __ATLDLGS_H__ + #error atlfind.h requires atldlgs.h to be included first +#endif + +#if !((defined(__ATLMISC_H__) && defined(_WTL_USE_CSTRING)) || defined(__ATLSTR_H__)) + #error atlfind.h requires CString (either from ATL's atlstr.h or WTL's atlmisc.h with _WTL_USE_CSTRING) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CEditFindReplaceImplBase +// CEditFindReplaceImpl +// CRichEditFindReplaceImpl + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CEditFindReplaceImplBase - Base class for mixin classes that +// help implement Find/Replace for CEdit or CRichEditCtrl based window classes. + +template +class CEditFindReplaceImplBase +{ +protected: +// Typedefs + typedef CEditFindReplaceImplBase thisClass; + +// Data members + TFindReplaceDialog* m_pFindReplaceDialog; + _CSTRING_NS::CString m_sFindNext, m_sReplaceWith; + BOOL m_bFindOnly, m_bFirstSearch, m_bMatchCase, m_bWholeWord, m_bFindDown; + LONG m_nInitialSearchPos; + HCURSOR m_hOldCursor; + +// Enumerations + enum TranslationTextItem + { + eText_OnReplaceAllMessage = 0, + eText_OnReplaceAllTitle = 1, + eText_OnTextNotFoundMessage = 2, + eText_OnTextNotFoundTitle = 3 + }; + +public: +// Constructors + CEditFindReplaceImplBase() : + m_pFindReplaceDialog(NULL), + m_bFindOnly(TRUE), + m_bFirstSearch(TRUE), + m_bMatchCase(FALSE), + m_bWholeWord(FALSE), + m_bFindDown(TRUE), + m_nInitialSearchPos(0), + m_hOldCursor(NULL) + { + } + +// Message Handlers + BEGIN_MSG_MAP(thisClass) + ALT_MSG_MAP(1) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(TFindReplaceDialog::GetFindReplaceMsg(), OnFindReplaceCmd) + COMMAND_ID_HANDLER(ID_EDIT_FIND, OnEditFind) + COMMAND_ID_HANDLER(ID_EDIT_REPEAT, OnEditRepeat) + COMMAND_ID_HANDLER(ID_EDIT_REPLACE, OnEditReplace) + END_MSG_MAP() + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_pFindReplaceDialog != NULL) + { + m_pFindReplaceDialog->SendMessage(WM_CLOSE); + ATLASSERT(m_pFindReplaceDialog == NULL); + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnFindReplaceCmd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + + TFindReplaceDialog* pDialog = TFindReplaceDialog::GetNotifier(lParam); + if(pDialog == NULL) + { + ATLASSERT(FALSE); + ::MessageBeep(MB_ICONERROR); + return 1; + } + ATLASSERT(pDialog == m_pFindReplaceDialog); + + LPFINDREPLACE findReplace = (LPFINDREPLACE)lParam; + if((m_pFindReplaceDialog != NULL) && (findReplace != NULL)) + { + if(pDialog->FindNext()) + { + pT->OnFindNext(pDialog->GetFindString(), pDialog->SearchDown(), + pDialog->MatchCase(), pDialog->MatchWholeWord()); + } + else if(pDialog->ReplaceCurrent()) + { + pT->OnReplaceSel(pDialog->GetFindString(), + pDialog->SearchDown(), pDialog->MatchCase(), pDialog->MatchWholeWord(), + pDialog->GetReplaceString()); + } + else if(pDialog->ReplaceAll()) + { + pT->OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(), + pDialog->MatchCase(), pDialog->MatchWholeWord()); + } + else if(pDialog->IsTerminating()) + { + // Dialog is going away (but hasn't gone away yet) + // OnFinalMessage will "delete this" + pT->OnTerminatingFindReplaceDialog(m_pFindReplaceDialog); + m_pFindReplaceDialog = NULL; + } + } + + return 0; + } + + LRESULT OnEditFind(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->FindReplace(TRUE); + + return 0; + } + + LRESULT OnEditRepeat(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + + // If the user is holding down SHIFT when hitting F3, we'll + // search in reverse. Otherwise, we'll search forward. + // (be sure to have an accelerator mapped to ID_EDIT_REPEAT + // for both F3 and Shift+F3) + m_bFindDown = !((::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000); + + if(m_sFindNext.IsEmpty()) + { + pT->FindReplace(TRUE); + } + else + { + if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) + pT->TextNotFound(m_sFindNext); + } + + return 0; + } + + LRESULT OnEditReplace(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled) + { + T* pT = static_cast(this); + + DWORD style = pT->GetStyle(); + if((style & ES_READONLY) != ES_READONLY) + { + pT->FindReplace(FALSE); + } + else + { + // Don't allow replace when the edit control is read only + bHandled = FALSE; + } + + return 0; + } + +// Operations (overrideable) + TFindReplaceDialog* CreateFindReplaceDialog(BOOL bFindOnly, // TRUE for Find, FALSE for FindReplace + LPCTSTR lpszFindWhat, + LPCTSTR lpszReplaceWith = NULL, + DWORD dwFlags = FR_DOWN, + HWND hWndParent = NULL) + { + // You can override all of this in a derived class + + TFindReplaceDialog* findReplaceDialog = new TFindReplaceDialog(); + if(findReplaceDialog == NULL) + { + ::MessageBeep(MB_ICONHAND); + } + else + { + HWND hWndFindReplace = findReplaceDialog->Create(bFindOnly, + lpszFindWhat, lpszReplaceWith, dwFlags, hWndParent); + if(hWndFindReplace == NULL) + { + delete findReplaceDialog; + findReplaceDialog = NULL; + } + else + { + findReplaceDialog->SetActiveWindow(); + findReplaceDialog->ShowWindow(SW_SHOW); + } + } + + return findReplaceDialog; + } + + void AdjustDialogPosition(HWND hWndDialog) + { + ATLASSERT((hWndDialog != NULL) && ::IsWindow(hWndDialog)); + + T* pT = static_cast(this); + LONG nStartChar = 0, nEndChar = 0; + // Send EM_GETSEL so we can use both Edit and RichEdit + // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&) + ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); + POINT point = pT->PosFromChar(nStartChar); + ::ClientToScreen(pT->GetParent(), &point); + CRect rect; + ::GetWindowRect(hWndDialog, &rect); + if(rect.PtInRect(point)) + { + if(point.y > rect.Height()) + { + rect.OffsetRect(0, point.y - rect.bottom - 20); + } + else + { + int nVertExt = GetSystemMetrics(SM_CYSCREEN); + if(point.y + rect.Height() < nVertExt) + rect.OffsetRect(0, 40 + point.y - rect.top); + } + + ::MoveWindow(hWndDialog, rect.left, rect.top, rect.Width(), rect.Height(), TRUE); + } + } + + DWORD GetFindReplaceDialogFlags(void) const + { + DWORD dwFlags = 0; + + if(m_bFindDown) + dwFlags |= FR_DOWN; + if(m_bMatchCase) + dwFlags |= FR_MATCHCASE; + if(m_bWholeWord) + dwFlags |= FR_WHOLEWORD; + + return dwFlags; + } + + void FindReplace(BOOL bFindOnly) + { + T* pT = static_cast(this); + m_bFirstSearch = TRUE; + if(m_pFindReplaceDialog != NULL) + { + if(m_bFindOnly == bFindOnly) + { + m_pFindReplaceDialog->SetActiveWindow(); + m_pFindReplaceDialog->ShowWindow(SW_SHOW); + return; + } + else + { + m_pFindReplaceDialog->SendMessage(WM_CLOSE); + ATLASSERT(m_pFindReplaceDialog == NULL); + } + } + + ATLASSERT(m_pFindReplaceDialog == NULL); + + _CSTRING_NS::CString findNext; + pT->GetSelText(findNext); + // if selection is empty or spans multiple lines use old find text + if(findNext.IsEmpty() || (findNext.FindOneOf(_T("\n\r")) != -1)) + findNext = m_sFindNext; + _CSTRING_NS::CString replaceWith = m_sReplaceWith; + DWORD dwFlags = pT->GetFindReplaceDialogFlags(); + + m_pFindReplaceDialog = pT->CreateFindReplaceDialog(bFindOnly, + findNext, replaceWith, dwFlags, pT->operator HWND()); + ATLASSERT(m_pFindReplaceDialog != NULL); + if(m_pFindReplaceDialog != NULL) + m_bFindOnly = bFindOnly; + } + + BOOL SameAsSelected(LPCTSTR lpszCompare, BOOL bMatchCase, BOOL /*bWholeWord*/) + { + T* pT = static_cast(this); + + // check length first + size_t nLen = lstrlen(lpszCompare); + LONG nStartChar = 0, nEndChar = 0; + // Send EM_GETSEL so we can use both Edit and RichEdit + // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&) + ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); + if(nLen != (size_t)(nEndChar - nStartChar)) + return FALSE; + + // length is the same, check contents + _CSTRING_NS::CString selectedText; + pT->GetSelText(selectedText); + + return (bMatchCase && selectedText.Compare(lpszCompare) == 0) || + (!bMatchCase && selectedText.CompareNoCase(lpszCompare) == 0); + } + + void TextNotFound(LPCTSTR lpszFind) + { + T* pT = static_cast(this); + m_bFirstSearch = TRUE; + pT->OnTextNotFound(lpszFind); + } + + _CSTRING_NS::CString GetTranslationText(enum TranslationTextItem eItem) const + { + _CSTRING_NS::CString text; + switch(eItem) + { + case eText_OnReplaceAllMessage: + text = _T("Replaced %d occurances of \"%s\" with \"%s\""); + break; + case eText_OnReplaceAllTitle: + text = _T("Replace All"); + break; + case eText_OnTextNotFoundMessage: + text = _T("Unable to find the text \"%s\""); + break; + case eText_OnTextNotFoundTitle: + text = _T("Text not found"); + break; + } + + return text; + } + +// Overrideable Handlers + void OnFindNext(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord) + { + T* pT = static_cast(this); + + m_sFindNext = lpszFind; + m_bMatchCase = bMatchCase; + m_bWholeWord = bWholeWord; + m_bFindDown = bFindDown; + + if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) + pT->TextNotFound(m_sFindNext); + else + pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND()); + } + + void OnReplaceSel(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord, LPCTSTR lpszReplace) + { + T* pT = static_cast(this); + + m_sFindNext = lpszFind; + m_sReplaceWith = lpszReplace; + m_bMatchCase = bMatchCase; + m_bWholeWord = bWholeWord; + m_bFindDown = bFindDown; + + if(pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord)) + pT->ReplaceSel(m_sReplaceWith); + + if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) + pT->TextNotFound(m_sFindNext); + else + pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND()); + } + + void OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bMatchCase, BOOL bWholeWord) + { + T* pT = static_cast(this); + + m_sFindNext = lpszFind; + m_sReplaceWith = lpszReplace; + m_bMatchCase = bMatchCase; + m_bWholeWord = bWholeWord; + m_bFindDown = TRUE; + + // no selection or different than what looking for + if(!pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord)) + { + if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) + { + pT->TextNotFound(m_sFindNext); + return; + } + } + + pT->OnReplaceAllCoreBegin(); + + int replaceCount=0; + do + { + ++replaceCount; + pT->ReplaceSel(m_sReplaceWith); + } while(pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)); + + pT->OnReplaceAllCoreEnd(replaceCount); + } + + void OnReplaceAllCoreBegin() + { + T* pT = static_cast(this); + + m_hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); + + pT->HideSelection(TRUE, FALSE); + + } + + void OnReplaceAllCoreEnd(int replaceCount) + { + T* pT = static_cast(this); + pT->HideSelection(FALSE, FALSE); + + ::SetCursor(m_hOldCursor); + + _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnReplaceAllMessage); + if(message.GetLength() > 0) + { + _CSTRING_NS::CString formattedMessage; + formattedMessage.Format(message, + replaceCount, m_sFindNext, m_sReplaceWith); + if(m_pFindReplaceDialog != NULL) + { + m_pFindReplaceDialog->MessageBox(formattedMessage, + pT->GetTranslationText(eText_OnReplaceAllTitle), + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); + } + else + { + pT->MessageBox(formattedMessage, + pT->GetTranslationText(eText_OnReplaceAllTitle), + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); + } + } + } + + void OnTextNotFound(LPCTSTR lpszFind) + { + T* pT = static_cast(this); + _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnTextNotFoundMessage); + if(message.GetLength() > 0) + { + _CSTRING_NS::CString formattedMessage; + formattedMessage.Format(message, lpszFind); + if(m_pFindReplaceDialog != NULL) + { + m_pFindReplaceDialog->MessageBox(formattedMessage, + pT->GetTranslationText(eText_OnTextNotFoundTitle), + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); + } + else + { + pT->MessageBox(formattedMessage, + pT->GetTranslationText(eText_OnTextNotFoundTitle), + MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); + } + } + else + { + ::MessageBeep(MB_ICONHAND); + } + } + + void OnTerminatingFindReplaceDialog(TFindReplaceDialog*& /*findReplaceDialog*/) + { + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CEditFindReplaceImpl - Mixin class for implementing Find/Replace for CEdit +// based window classes. + +// Chain to CEditFindReplaceImpl message map. Your class must also derive from CEdit. +// Example: +// class CMyEdit : public CWindowImpl, +// public CEditFindReplaceImpl +// { +// public: +// BEGIN_MSG_MAP(CMyEdit) +// // your handlers... +// CHAIN_MSG_MAP_ALT(CEditFindReplaceImpl, 1) +// END_MSG_MAP() +// // other stuff... +// }; + +template +class CEditFindReplaceImpl : public CEditFindReplaceImplBase +{ +protected: + typedef CEditFindReplaceImpl thisClass; + typedef CEditFindReplaceImplBase baseClass; + +// Data members + LPTSTR m_pShadowBuffer; // Special shadow buffer only used in some cases. + UINT m_nShadowSize; + int m_bShadowBufferNeeded; // TRUE, FALSE, < 0 => Need to check + +public: +// Constructors + CEditFindReplaceImpl() : + m_pShadowBuffer(NULL), + m_nShadowSize(0), + m_bShadowBufferNeeded(-1) + { + } + + virtual ~CEditFindReplaceImpl() + { + if(m_pShadowBuffer != NULL) + { + delete [] m_pShadowBuffer; + m_pShadowBuffer = NULL; + } + } + +// Message Handlers + BEGIN_MSG_MAP(thisClass) + ALT_MSG_MAP(1) + CHAIN_MSG_MAP_ALT(baseClass, 1) + END_MSG_MAP() + +// Operations + // Supported only for RichEdit, so this does nothing for Edit + void HideSelection(BOOL /*bHide*/ = TRUE, BOOL /*bChangeStyle*/ = FALSE) + { + } + +// Operations (overrideable) + BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE) + { + T* pT = static_cast(this); + + ATLASSERT(lpszFind != NULL); + ATLASSERT(*lpszFind != _T('\0')); + + UINT nLen = pT->GetBufferLength(); + int nStartChar = 0, nEndChar = 0; + pT->GetSel(nStartChar, nEndChar); + UINT nStart = nStartChar; + int iDir = bFindDown ? +1 : -1; + + // can't find a match before the first character + if(nStart == 0 && iDir < 0) + return FALSE; + + LPCTSTR lpszText = pT->LockBuffer(); + + bool isDBCS = false; +#ifdef _MBCS + CPINFO info = { 0 }; + ::GetCPInfo(::GetOEMCP(), &info); + isDBCS = (info.MaxCharSize > 1); +#endif + + if(iDir < 0) + { + // always go back one for search backwards + nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart)); + } + else if(nStartChar != nEndChar && pT->SameAsSelected(lpszFind, bMatchCase, bWholeWord)) + { + // easy to go backward/forward with SBCS +#ifndef _UNICODE + if(::IsDBCSLeadByte(lpszText[nStart])) + nStart++; +#endif + nStart += iDir; + } + + // handle search with nStart past end of buffer + UINT nLenFind = ::lstrlen(lpszFind); + if(nStart + nLenFind - 1 >= nLen) + { + if(iDir < 0 && nLen >= nLenFind) + { + if(isDBCS) + { + // walk back to previous character n times + nStart = nLen; + int n = nLenFind; + while(n--) + { + nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart)); + } + } + else + { + // single-byte character set is easy and fast + nStart = nLen - nLenFind; + } + ATLASSERT(nStart + nLenFind - 1 <= nLen); + } + else + { + pT->UnlockBuffer(); + return FALSE; + } + } + + // start the search at nStart + LPCTSTR lpsz = lpszText + nStart; + typedef int (WINAPI* CompareProc)(LPCTSTR str1, LPCTSTR str2); + CompareProc pfnCompare = bMatchCase ? lstrcmp : lstrcmpi; + + if(isDBCS) + { + // double-byte string search + LPCTSTR lpszStop = NULL; + if(iDir > 0) + { + // start at current and find _first_ occurrance + lpszStop = lpszText + nLen - nLenFind + 1; + } + else + { + // start at top and find _last_ occurrance + lpszStop = lpsz; + lpsz = lpszText; + } + + LPCTSTR lpszFound = NULL; + while(lpsz <= lpszStop) + { +#ifndef _UNICODE + if(!bMatchCase || (*lpsz == *lpszFind && (!::IsDBCSLeadByte(*lpsz) || lpsz[1] == lpszFind[1]))) +#else + if(!bMatchCase || (*lpsz == *lpszFind && lpsz[1] == lpszFind[1])) +#endif + { + LPTSTR lpch = (LPTSTR)(lpsz + nLenFind); + TCHAR chSave = *lpch; + *lpch = _T('\0'); + int nResult = (*pfnCompare)(lpsz, lpszFind); + *lpch = chSave; + if(nResult == 0) + { + lpszFound = lpsz; + if(iDir > 0) + break; + } + } + lpsz = ::CharNext(lpsz); + } + pT->UnlockBuffer(); + + if(lpszFound != NULL) + { + int n = (int)(lpszFound - lpszText); + pT->SetSel(n, n + nLenFind); + return TRUE; + } + } + else + { + // single-byte string search + UINT nCompare; + if(iDir < 0) + nCompare = (UINT)(lpsz - lpszText) + 1; + else + nCompare = nLen - (UINT)(lpsz - lpszText) - nLenFind + 1; + + while(nCompare > 0) + { + ATLASSERT(lpsz >= lpszText); + ATLASSERT(lpsz + nLenFind - 1 <= lpszText + nLen - 1); + + LPSTR lpch = (LPSTR)(lpsz + nLenFind); + char chSave = *lpch; + *lpch = '\0'; + int nResult = (*pfnCompare)(lpsz, lpszFind); + *lpch = chSave; + if(nResult == 0) + { + pT->UnlockBuffer(); + int n = (int)(lpsz - lpszText); + pT->SetSel(n, n + nLenFind); + return TRUE; + } + + // restore character at end of search + *lpch = chSave; + + // move on to next substring + nCompare--; + lpsz += iDir; + } + pT->UnlockBuffer(); + } + + return FALSE; + } + + LPCTSTR LockBuffer() const + { + const T* pT = static_cast(this); + + ATLASSERT(pT->m_hWnd != NULL); + + BOOL useShadowBuffer = pT->UseShadowBuffer(); + if(useShadowBuffer) + { + if(m_pShadowBuffer == NULL || pT->GetModify()) + { + ATLASSERT(m_pShadowBuffer != NULL || m_nShadowSize == 0); + UINT nSize = pT->GetWindowTextLength() + 1; + if(nSize > m_nShadowSize) + { + // need more room for shadow buffer + T* pThisNoConst = const_cast(pT); + delete[] m_pShadowBuffer; + pThisNoConst->m_pShadowBuffer = NULL; + pThisNoConst->m_nShadowSize = 0; + pThisNoConst->m_pShadowBuffer = new TCHAR[nSize]; + pThisNoConst->m_nShadowSize = nSize; + } + + // update the shadow buffer with GetWindowText + ATLASSERT(m_nShadowSize >= nSize); + ATLASSERT(m_pShadowBuffer != NULL); + pT->GetWindowText(m_pShadowBuffer, nSize); + } + + return m_pShadowBuffer; + } + + HLOCAL hLocal = pT->GetHandle(); + ATLASSERT(hLocal != NULL); + LPCTSTR lpszText = (LPCTSTR)::LocalLock(hLocal); + ATLASSERT(lpszText != NULL); + + return lpszText; + } + + void UnlockBuffer() const + { + const T* pT = static_cast(this); + + ATLASSERT(pT->m_hWnd != NULL); + + BOOL useShadowBuffer = pT->UseShadowBuffer(); + if(!useShadowBuffer) + { + HLOCAL hLocal = pT->GetHandle(); + ATLASSERT(hLocal != NULL); + ::LocalUnlock(hLocal); + } + } + + UINT GetBufferLength() const + { + const T* pT = static_cast(this); + + ATLASSERT(pT->m_hWnd != NULL); + UINT nLen = 0; + LPCTSTR lpszText = pT->LockBuffer(); + if(lpszText != NULL) + nLen = ::lstrlen(lpszText); + pT->UnlockBuffer(); + + return nLen; + } + + LONG EndOfLine(LPCTSTR lpszText, UINT nLen, UINT nIndex) const + { + LPCTSTR lpsz = lpszText + nIndex; + LPCTSTR lpszStop = lpszText + nLen; + while(lpsz < lpszStop && *lpsz != _T('\r')) + ++lpsz; + return LONG(lpsz - lpszText); + } + + LONG GetSelText(_CSTRING_NS::CString& strText) const + { + const T* pT = static_cast(this); + + int nStartChar = 0, nEndChar = 0; + pT->GetSel(nStartChar, nEndChar); + ATLASSERT((UINT)nEndChar <= pT->GetBufferLength()); + LPCTSTR lpszText = pT->LockBuffer(); + LONG nLen = pT->EndOfLine(lpszText, nEndChar, nStartChar) - nStartChar; + SecureHelper::memcpy_x(strText.GetBuffer(nLen), nLen * sizeof(TCHAR), lpszText + nStartChar, nLen * sizeof(TCHAR)); + strText.ReleaseBuffer(nLen); + pT->UnlockBuffer(); + + return nLen; + } + + BOOL UseShadowBuffer(void) const + { + const T* pT = static_cast(this); + + if(pT->m_bShadowBufferNeeded < 0) + { + T* pThisNoConst = const_cast(pT); + + OSVERSIONINFO ovi = { 0 }; + ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + ::GetVersionEx(&ovi); + + bool bWin9x = (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); + if(bWin9x) + { + // Windows 95, 98, ME + // Under Win9x, it is necessary to maintain a shadow buffer. + // It is only updated when the control contents have been changed. + pThisNoConst->m_bShadowBufferNeeded = TRUE; + } + else + { + // Windows NT, 2000, XP, etc. + pThisNoConst->m_bShadowBufferNeeded = FALSE; + +#ifndef _UNICODE + // On Windows XP (or later), if common controls version 6 is in use + // (such as via theming), then EM_GETHANDLE will always return a UNICODE string. + // If theming is enabled and Common Controls version 6 is in use, + // you're really not suppose to superclass or subclass common controls + // with an ANSI windows procedure (so its best to only theme if you use UNICODE). + // Using a shadow buffer uses GetWindowText instead, so it solves + // this problem for us (although it makes it a little less efficient). + + if((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5)) + { + // We use DLLVERSIONINFO_private so we don't have to depend on shlwapi.h + typedef struct _DLLVERSIONINFO_private + { + DWORD cbSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformID; + } DLLVERSIONINFO_private; + + HMODULE hModule = ::LoadLibrary("comctl32.dll"); + if(hModule != NULL) + { + typedef HRESULT (CALLBACK *LPFN_DllGetVersion)(DLLVERSIONINFO_private *); + LPFN_DllGetVersion fnDllGetVersion = (LPFN_DllGetVersion)::GetProcAddress(hModule, "DllGetVersion"); + if(fnDllGetVersion != NULL) + { + DLLVERSIONINFO_private version = { 0 }; + version.cbSize = sizeof(DLLVERSIONINFO_private); + if(SUCCEEDED(fnDllGetVersion(&version))) + { + if(version.dwMajorVersion >= 6) + { + pThisNoConst->m_bShadowBufferNeeded = TRUE; + + ATLTRACE2(atlTraceUI, 0, _T("Warning: You have compiled for MBCS/ANSI but are using common controls version 6 or later (likely through a manifest file).\r\n")); + ATLTRACE2(atlTraceUI, 0, _T("If you use common controls version 6 or later, you should only do so for UNICODE builds.\r\n")); + } + } + } + + ::FreeLibrary(hModule); + hModule = NULL; + } + } +#endif // !_UNICODE + } + } + + return (pT->m_bShadowBufferNeeded == TRUE); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CRichEditFindReplaceImpl - Mixin class for implementing Find/Replace for CRichEditCtrl +// based window classes. + +// Chain to CRichEditFindReplaceImpl message map. Your class must also derive from CRichEditCtrl. +// Example: +// class CMyRichEdit : public CWindowImpl, +// public CRichEditFindReplaceImpl +// { +// public: +// BEGIN_MSG_MAP(CMyRichEdit) +// // your handlers... +// CHAIN_MSG_MAP_ALT(CRichEditFindReplaceImpl, 1) +// END_MSG_MAP() +// // other stuff... +// }; + +template +class CRichEditFindReplaceImpl : public CEditFindReplaceImplBase +{ +protected: + typedef CRichEditFindReplaceImpl thisClass; + typedef CEditFindReplaceImplBase baseClass; + +public: + BEGIN_MSG_MAP(thisClass) + ALT_MSG_MAP(1) + CHAIN_MSG_MAP_ALT(baseClass, 1) + END_MSG_MAP() + +// Operations (overrideable) + BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE) + { + T* pT = static_cast(this); + + ATLASSERT(lpszFind != NULL); + FINDTEXTEX ft = { 0 }; + + pT->GetSel(ft.chrg); + if(m_bFirstSearch) + { + if(bFindDown) + m_nInitialSearchPos = ft.chrg.cpMin; + else + m_nInitialSearchPos = ft.chrg.cpMax; + m_bFirstSearch = FALSE; + } + +#if (_RICHEDIT_VER >= 0x0200) + ft.lpstrText = (LPTSTR)lpszFind; +#else // !(_RICHEDIT_VER >= 0x0200) + USES_CONVERSION; + ft.lpstrText = T2A((LPTSTR)lpszFind); +#endif // !(_RICHEDIT_VER >= 0x0200) + + if(ft.chrg.cpMin != ft.chrg.cpMax) // i.e. there is a selection + { + if(bFindDown) + { + ft.chrg.cpMin++; + } + else + { + // won't wraparound backwards + ft.chrg.cpMin = max(ft.chrg.cpMin, 0); + } + } + + DWORD dwFlags = bMatchCase ? FR_MATCHCASE : 0; + dwFlags |= bWholeWord ? FR_WHOLEWORD : 0; + + ft.chrg.cpMax = pT->GetTextLength() + m_nInitialSearchPos; + + if(bFindDown) + { + if(m_nInitialSearchPos >= 0) + ft.chrg.cpMax = pT->GetTextLength(); + + dwFlags |= FR_DOWN; + ATLASSERT(ft.chrg.cpMax >= ft.chrg.cpMin); + } + else + { + if(m_nInitialSearchPos >= 0) + ft.chrg.cpMax = 0; + + dwFlags &= ~FR_DOWN; + ATLASSERT(ft.chrg.cpMax <= ft.chrg.cpMin); + } + + BOOL bRet = FALSE; + + if(pT->FindAndSelect(dwFlags, ft) != -1) + { + bRet = TRUE; // we found the text + } + else if(m_nInitialSearchPos > 0) + { + // if the original starting point was not the beginning + // of the buffer and we haven't already been here + if(bFindDown) + { + ft.chrg.cpMin = 0; + ft.chrg.cpMax = m_nInitialSearchPos; + } + else + { + ft.chrg.cpMin = pT->GetTextLength(); + ft.chrg.cpMax = m_nInitialSearchPos; + } + m_nInitialSearchPos = m_nInitialSearchPos - pT->GetTextLength(); + + bRet = (pT->FindAndSelect(dwFlags, ft) != -1) ? TRUE : FALSE; + } + + return bRet; + } + + long FindAndSelect(DWORD dwFlags, FINDTEXTEX& ft) + { + T* pT = static_cast(this); + LONG index = pT->FindText(dwFlags, ft); + if(index != -1) // i.e. we found something + pT->SetSel(ft.chrgText); + + return index; + } +}; + +}; // namespace WTL + +#endif // __ATLFIND_H__ diff --git a/wtl/wtl/include/atlframe.h b/wtl/wtl/include/atlframe.h new file mode 100644 index 00000000..4ec4365a --- /dev/null +++ b/wtl/wtl/include/atlframe.h @@ -0,0 +1,3476 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLFRAME_H__ +#define __ATLFRAME_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlframe.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlframe.h requires atlwin.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CFrameWindowImpl +// CMDIWindow +// CMDIFrameWindowImpl +// CMDIChildWindowImpl +// COwnerDraw +// CUpdateUIBase +// CUpdateUI +// CDynamicUpdateUI +// CDialogResize +// CDoubleBufferImpl +// CDoubleBufferWindowImpl +// +// Global functions: +// AtlCreateSimpleToolBar() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CFrameWndClassInfo - Manages frame window Windows class information + +class CFrameWndClassInfo +{ +public: +#ifndef _WIN32_WCE + enum { cchAutoName = 5 + sizeof(void*) * 2 }; // sizeof(void*) * 2 is the number of digits %p outputs + WNDCLASSEX m_wc; +#else // CE specific + enum { cchAutoName = MAX_PATH }; // MAX_PATH because this can be set in the wizard generated CMainFrame::ActivatePreviousInstance to a user defined string. + WNDCLASS m_wc; +#endif // !_WIN32_WCE + LPCTSTR m_lpszOrigName; + WNDPROC pWndProc; + LPCTSTR m_lpszCursorID; + BOOL m_bSystemCursor; + ATOM m_atom; + TCHAR m_szAutoName[cchAutoName]; + UINT m_uCommonResourceID; + +#ifndef _WIN32_WCE + ATOM Register(WNDPROC* pProc) + { + if (m_atom == 0) + { + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(m_atom == 0) + { + HINSTANCE hInst = ModuleHelper::GetModuleInstance(); + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + LPCTSTR lpsz = m_wc.lpszClassName; + WNDPROC proc = m_wc.lpfnWndProc; + + WNDCLASSEX wc = { 0 }; + wc.cbSize = sizeof(WNDCLASSEX); + // try process local class first + if(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc)) + { + // try global class + if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc)) + { + lock.Unlock(); + return 0; + } + } + m_wc = wc; + pWndProc = m_wc.lpfnWndProc; + m_wc.lpszClassName = lpsz; + m_wc.lpfnWndProc = proc; + } + else + { + m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); + } + + m_wc.hInstance = hInst; + m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes + if (m_wc.lpszClassName == NULL) + { +#if (_WIN32_WINNT >= 0x0500) || defined(_WIN64) + SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%p"), &m_wc); +#else // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64)) + SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc); +#endif // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64)) + m_wc.lpszClassName = m_szAutoName; + } + + WNDCLASSEX wcTemp = m_wc; + m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); + if (m_atom == 0) + { + if(m_uCommonResourceID != 0) // use it if not zero + { + m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); + m_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + } + m_atom = ::RegisterClassEx(&m_wc); + } + } + + lock.Unlock(); + } + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + ATLASSERT(pWndProc != NULL); + *pProc = pWndProc; + } + + return m_atom; + } +#else // CE specific + ATOM Register(WNDPROC* pProc) + { + if (m_atom == 0) + { + CWindowCreateCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n")); + ATLASSERT(FALSE); + return 0; + } + + if(m_atom == 0) + { + HINSTANCE hInst = ModuleHelper::GetModuleInstance(); + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + LPCTSTR lpsz = m_wc.lpszClassName; + WNDPROC proc = m_wc.lpfnWndProc; + + WNDCLASS wc = { 0 }; + // try process local class first + if(!::GetClassInfo(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc)) + { + // try global class + if(!::GetClassInfo(NULL, m_lpszOrigName, &wc)) + { + lock.Unlock(); + return 0; + } + } + m_wc = wc; + pWndProc = m_wc.lpfnWndProc; + m_wc.lpszClassName = lpsz; + m_wc.lpfnWndProc = proc; + } + else + { +#if defined(GWES_CURSOR) || defined(GWES_MCURSOR) + m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); +#else // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR)) + m_wc.hCursor = NULL; +#endif // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR)) + } + + m_wc.hInstance = hInst; + m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes + if (m_wc.lpszClassName == NULL) + { + wsprintf(m_szAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc); + m_wc.lpszClassName = m_szAutoName; + } + + WNDCLASS wcTemp = m_wc; + m_atom = (ATOM)::GetClassInfo(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); + if (m_atom == 0) + { + if(m_uCommonResourceID != 0) // use it if not zero + m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); + m_atom = ::RegisterClass(&m_wc); + } + } + + lock.Unlock(); + } + + if (m_lpszOrigName != NULL) + { + ATLASSERT(pProc != NULL); + ATLASSERT(pWndProc != NULL); + *pProc = pWndProc; + } + + return m_atom; + } +#endif // _WIN32_WCE +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Macros for declaring frame window WNDCLASS + +#ifndef _WIN32_WCE + +#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { sizeof(WNDCLASSEX), 0, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { sizeof(WNDCLASSEX), style, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { sizeof(WNDCLASSEX), 0, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \ + OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#else // CE specific + +#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { 0, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { style, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ +static WTL::CFrameWndClassInfo& GetWndClassInfo() \ +{ \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { NULL, StartWindowProc, \ + 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName }, \ + OrigWndClassName, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ +} + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CFrameWindowImpl + +// Client window command chaining macro (only for frame windows) +#define CHAIN_CLIENT_COMMANDS() \ + if(uMsg == WM_COMMAND && m_hWndClient != NULL) \ + ::SendMessage(m_hWndClient, uMsg, wParam, lParam); + +// standard toolbar styles +#define ATL_SIMPLE_TOOLBAR_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS) +// toolbar in a rebar pane +#define ATL_SIMPLE_TOOLBAR_PANE_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT) +// standard rebar styles +#if (_WIN32_IE >= 0x0400) + #define ATL_SIMPLE_REBAR_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE) +#else + #define ATL_SIMPLE_REBAR_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS) +#endif // !(_WIN32_IE >= 0x0400) +// rebar without borders +#if (_WIN32_IE >= 0x0400) + #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER) +#else + #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \ + (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | CCS_NODIVIDER) +#endif // !(_WIN32_IE >= 0x0400) + +// command bar support +#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + +#define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND +#define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu +#define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu + +struct _AtlFrameWnd_CmdBarPopupMenu +{ + int cbSize; + HMENU hMenu; + UINT uFlags; + int x; + int y; + LPTPMPARAMS lptpm; +}; + +#define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu + +#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + + +template +class ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits > +{ +public: + DECLARE_FRAME_WND_CLASS(NULL, 0) + +// Data members + HWND m_hWndToolBar; + HWND m_hWndStatusBar; + HWND m_hWndClient; + + HACCEL m_hAccel; + +#ifdef _WIN32_WCE + HWND m_hWndCECommandBar; +#endif // _WIN32_WCE + + struct _AtlToolBarData + { + WORD wVersion; + WORD wWidth; + WORD wHeight; + WORD wItemCount; + //WORD aItems[wItemCount] + + WORD* items() + { return (WORD*)(this+1); } + }; + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + struct _ChevronMenuInfo + { + HMENU hMenu; + LPNMREBARCHEVRON lpnm; + bool bCmdBar; + }; +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + +// Constructor + CFrameWindowImplBase() : +#ifdef _WIN32_WCE + m_hWndCECommandBar(NULL), +#endif // _WIN32_WCE + m_hWndToolBar(NULL), + m_hWndStatusBar(NULL), + m_hWndClient(NULL), + m_hAccel(NULL) + { } + +// Methods + HWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam) + { + ATLASSERT(m_hWnd == NULL); + + if(atom == 0) + return NULL; + + ModuleHelper::AddCreateWndData(&m_thunk.cd, this); + + if(MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD)) + MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this; + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName, + dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left, + rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu, + ModuleHelper::GetModuleInstance(), lpCreateParam); + + ATLASSERT(hWnd == NULL || m_hWnd == hWnd); + + return hWnd; + } + + static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, + DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + HINSTANCE hInst = ModuleHelper::GetResourceInstance(); + HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR); + if (hRsrc == NULL) + return NULL; + + HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc); + if (hGlobal == NULL) + return NULL; + + _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal); + if (pData == NULL) + return NULL; + ATLASSERT(pData->wVersion == 1); + + WORD* pItems = pData->items(); + int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0); + CTempBuffer buff; + TBBUTTON* pTBBtn = buff.Allocate(nItems); + ATLASSERT(pTBBtn != NULL); + if(pTBBtn == NULL) + return NULL; + + const int cxSeparator = 8; + + // set initial separator (half width) + if(bInitialSeparator) + { + pTBBtn[0].iBitmap = cxSeparator / 2; + pTBBtn[0].idCommand = 0; + pTBBtn[0].fsState = 0; + pTBBtn[0].fsStyle = TBSTYLE_SEP; + pTBBtn[0].dwData = 0; + pTBBtn[0].iString = 0; + } + + int nBmp = 0; + for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++) + { + if(pItems[i] != 0) + { + pTBBtn[j].iBitmap = nBmp++; + pTBBtn[j].idCommand = pItems[i]; + pTBBtn[j].fsState = TBSTATE_ENABLED; + pTBBtn[j].fsStyle = TBSTYLE_BUTTON; + pTBBtn[j].dwData = 0; + pTBBtn[j].iString = 0; + } + else + { + pTBBtn[j].iBitmap = cxSeparator; + pTBBtn[j].idCommand = 0; + pTBBtn[j].fsState = 0; + pTBBtn[j].fsStyle = TBSTYLE_SEP; + pTBBtn[j].dwData = 0; + pTBBtn[j].iString = 0; + } + } + +#ifndef _WIN32_WCE + HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); + if(hWnd == NULL) + { + ATLASSERT(FALSE); + return NULL; + } +#else // CE specific + dwStyle; + nID; + // The toolbar must go onto the existing CommandBar or MenuBar + HWND hWnd = hWndParent; +#endif // _WIN32_WCE + + ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L); + + // check if font is taller than our bitmaps + CFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L); + if(font.IsNull()) + font = AtlGetDefaultGuiFont(); + LOGFONT lf = { 0 }; + font.GetLogFont(lf); + WORD cyFontHeight = (WORD)abs(lf.lfHeight); + +#ifndef _WIN32_WCE + WORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID); + if(bitsPerPixel > 4) + { + COLORREF crMask = CLR_DEFAULT; + if(bitsPerPixel == 32) + { + // 32-bit color bitmap with alpha channel (valid for Windows XP and later) + crMask = CLR_NONE; + } + HIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE); + ATLASSERT(hImageList != NULL); + ::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList); + } + else +#endif // !_WIN32_WCE + { + TBADDBITMAP tbab = { 0 }; + tbab.hInst = hInst; + tbab.nID = nResourceID; + ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab); + } + + ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn); + ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, max(pData->wHeight, cyFontHeight))); + const int cxyButtonMargin = 7; + ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, max(pData->wHeight, cyFontHeight) + cxyButtonMargin)); + + return hWnd; + } + +#ifndef _WIN32_WCE + static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + // Ensure style combinations for proper rebar painting + if(dwStyle & CCS_NODIVIDER && dwStyle & WS_BORDER) + dwStyle &= ~WS_BORDER; + else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER)) + dwStyle |= CCS_NODIVIDER; + + // Create rebar window + HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); + if(hWndReBar == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n")); + return NULL; + } + + // Initialize and send the REBARINFO structure + REBARINFO rbi = { 0 }; + rbi.cbSize = sizeof(REBARINFO); + rbi.fMask = 0; + if(!::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi)) + { + ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n")); + ::DestroyWindow(hWndReBar); + return NULL; + } + + return hWndReBar; + } + + BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + m_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle, nID); + return (m_hWndToolBar != NULL); + } + + static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) + { + ATLASSERT(::IsWindow(hWndReBar)); // must be already created +#ifdef _DEBUG + // block - check if this is really a rebar + { + TCHAR lpszClassName[sizeof(REBARCLASSNAME)] = { 0 }; + ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME)); + ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0); + } +#endif // _DEBUG + ATLASSERT(::IsWindow(hWndBand)); // must be already created + + // Get number of buttons on the toolbar + int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L); + + // Set band info structure + REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; +#if (_WIN32_IE >= 0x0400) + rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE; +#else + rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE; +#endif // !(_WIN32_IE >= 0x0400) + if(lpstrTitle != NULL) + rbBand.fMask |= RBBIM_TEXT; +#ifdef _USE_AERO + rbBand.fStyle = 0; +#else + rbBand.fStyle = RBBS_CHILDEDGE; +#endif +#if (_WIN32_IE >= 0x0500) + if(nBtnCount > 0) // add chevron style for toolbar with buttons + rbBand.fStyle |= RBBS_USECHEVRON; +#endif // (_WIN32_IE >= 0x0500) + if(bNewRow) + rbBand.fStyle |= RBBS_BREAK; + + rbBand.lpText = (LPTSTR)lpstrTitle; + rbBand.hwndChild = hWndBand; + if(nID == 0) // calc band ID + nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L); + rbBand.wID = nID; + + // Calculate the size of the band + BOOL bRet = FALSE; + RECT rcTmp = { 0 }; + if(nBtnCount > 0) + { + bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp); + ATLASSERT(bRet); + rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right; + rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; + if(bFullWidthAlways) + { + rbBand.cxMinChild = rbBand.cx; + } + else if(lpstrTitle == NULL) + { + bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp); + ATLASSERT(bRet); + rbBand.cxMinChild = rcTmp.right; + } + else + { + rbBand.cxMinChild = 0; + } + } + else // no buttons, either not a toolbar or really has no buttons + { + bRet = ::GetWindowRect(hWndBand, &rcTmp); + ATLASSERT(bRet); + rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left); + rbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0; + rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; + } + +#if (_WIN32_IE >= 0x0400) + rbBand.cxIdeal = rbBand.cx; +#endif // (_WIN32_IE >= 0x0400) + + // Add the band + LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); + if(lRes == 0) + { + ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n")); + return FALSE; + } + +#if (_WIN32_IE >= 0x0501) + DWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L); + ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS); +#endif // (_WIN32_IE >= 0x0501) + + return TRUE; + } + + BOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) + { + ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar + ATLASSERT(::IsWindow(hWndBand)); // must be created + return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways); + } + +#if (_WIN32_IE >= 0x0400) + void SizeSimpleReBarBands() + { + ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar + + int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L); + + for(int i = 0; i < nCount; i++) + { + REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; + rbBand.fMask = RBBIM_SIZE; + BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand); + ATLASSERT(bRet); + RECT rect = { 0, 0, 0, 0 }; + ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect); + rbBand.cx += rect.left + rect.right; + bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand); + ATLASSERT(bRet); + } + } +#endif // (_WIN32_IE >= 0x0400) +#endif // _WIN32_WCE + +#ifndef _WIN32_WCE + BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) +#else // CE specific + BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR) +#endif // _WIN32_WCE + { + ATLASSERT(!::IsWindow(m_hWndStatusBar)); + m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID); + return (m_hWndStatusBar != NULL); + } + +#ifndef _WIN32_WCE + BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) +#else // CE specific + BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR) +#endif // _WIN32_WCE + { + const int cchMax = 128; // max text length is 127 for status bars (+1 for null) + TCHAR szText[cchMax]; + szText[0] = 0; + ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); + return CreateSimpleStatusBar(szText, dwStyle, nID); + } + +#ifdef _WIN32_WCE + BOOL CreateSimpleCECommandBar(LPTSTR pszMenu = NULL, WORD iButton = 0, DWORD dwFlags = 0, int nCmdBarID = 1) + { + ATLASSERT(m_hWndCECommandBar == NULL); + ATLASSERT(m_hWndToolBar == NULL); + + m_hWndCECommandBar = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), m_hWnd, nCmdBarID); + if(m_hWndCECommandBar == NULL) + return FALSE; + + m_hWndToolBar = m_hWndCECommandBar; + + BOOL bRet = TRUE; + + if(pszMenu != NULL) + bRet &= ::CommandBar_InsertMenubarEx(m_hWndCECommandBar, IS_INTRESOURCE(pszMenu) ? ModuleHelper::GetResourceInstance() : NULL, pszMenu, iButton); + + bRet &= ::CommandBar_AddAdornments(m_hWndCECommandBar, dwFlags, 0); + + return bRet; + } + +#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) + BOOL CreateSimpleCEMenuBar(UINT nToolBarId = ATL_IDW_MENU_BAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0) + { + ATLASSERT(m_hWndCECommandBar == NULL); + + SHMENUBARINFO mbi = { 0 }; + mbi.cbSize = sizeof(mbi); + mbi.hwndParent = m_hWnd; + mbi.dwFlags = dwFlags; + mbi.nToolBarId = nToolBarId; + mbi.hInstRes = ModuleHelper::GetResourceInstance(); + mbi.nBmpId = nBmpId; + mbi.cBmpImages = cBmpImages; + mbi.hwndMB = NULL; // This gets set by SHCreateMenuBar + + BOOL bRet = ::SHCreateMenuBar(&mbi); + if(bRet != FALSE) + { + m_hWndCECommandBar = mbi.hwndMB; + SizeToMenuBar(); + } + + return bRet; + } + + void SizeToMenuBar() // for menu bar only + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(::IsWindow(m_hWndCECommandBar)); + + RECT rect = { 0 }; + GetWindowRect(&rect); + RECT rectMB = { 0 }; + ::GetWindowRect(m_hWndCECommandBar, &rectMB); + int cy = ::IsWindowVisible(m_hWndCECommandBar) ? rectMB.top - rect.top : rectMB.bottom - rect.top; + SetWindowPos(NULL, 0, 0, rect.right - rect.left, cy, SWP_NOZORDER | SWP_NOMOVE); + } +#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) +#endif // _WIN32_WCE + + void UpdateLayout(BOOL bResizeBars = TRUE) + { + RECT rect = { 0 }; + GetClientRect(&rect); + + // position bars and offset their dimensions + UpdateBarsPosition(rect, bResizeBars); + + // resize client window + if(m_hWndClient != NULL) + ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOACTIVATE); + } + + void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE) + { + // resize toolbar + if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE)) + { + if(bResizeBars) + { + ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0); + ::InvalidateRect(m_hWndToolBar, NULL, FALSE); + } + RECT rectTB = { 0 }; + ::GetWindowRect(m_hWndToolBar, &rectTB); + rect.top += rectTB.bottom - rectTB.top; + } + + // resize status bar + if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE)) + { + if(bResizeBars) + ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0); + RECT rectSB = { 0 }; + ::GetWindowRect(m_hWndStatusBar, &rectSB); + rect.bottom -= rectSB.bottom - rectSB.top; + } + } + + BOOL PreTranslateMessage(MSG* pMsg) + { + if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg)) + return TRUE; + return FALSE; + } + + BEGIN_MSG_MAP(CFrameWindowImplBase) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) +#ifndef _WIN32_WCE + NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA) + NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW) +#endif // !_WIN32_WCE + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_hWndClient != NULL) // view will paint itself instead + return 1; + + bHandled = FALSE; + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + bHandled = FALSE; + + if(m_hWndStatusBar == NULL) + return 1; + + const int cchBuff = 256; + TCHAR szBuff[cchBuff]; + szBuff[0] = 0; + + WORD wFlags = HIWORD(wParam); + if(wFlags == 0xFFFF && lParam == NULL) // menu closing + {/* + ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L); + */ + ::LoadString(ModuleHelper::GetResourceInstance(), ATL_IDS_IDLEMESSAGE, szBuff, cchBuff); + ::SendMessage(m_hWndStatusBar, SB_SETTEXT, ID_DEFAULT_PANE, (LPARAM)szBuff); + } + else + { + if(!(wFlags & MF_POPUP)) + { + WORD wID = LOWORD(wParam); + // check for special cases + if(wID >= 0xF000 && wID < 0xF1F0) // system menu IDs + wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST); + else if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST) // MRU items + wID = ATL_IDS_MRU_FILE; + else if(wID >= ATL_IDM_FIRST_MDICHILD && wID <= ATL_IDM_LAST_MDICHILD) // MDI child windows + wID = ATL_IDS_MDICHILD; + + int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff); + for(int i = 0; i < nRet; i++) + { + if(szBuff[i] == _T('\n')) + { + szBuff[i] = 0; + break; + } + } + } + /* + ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L); + ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff); + */ + ::SendMessage(m_hWndStatusBar, SB_SETTEXT, ID_DEFAULT_PANE, (LPARAM)szBuff); + } + + return 1; + } +#endif // !_WIN32_WCE + + LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled) + { + if(m_hWndClient != NULL) + ::SetFocus(m_hWndClient); + + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) + { + if((GetStyle() & (WS_CHILD | WS_POPUP)) == 0) + ::PostQuitMessage(1); + + bHandled = FALSE; + return 1; + } + +#ifndef _WIN32_WCE + LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh; + pDispInfo->szText[0] = 0; + + if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) + { + const int cchBuff = 256; + char szBuff[cchBuff]; + szBuff[0] = 0; + int nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); + for(int i = 0; i < nRet; i++) + { + if(szBuff[i] == '\n') + { + SecureHelper::strncpyA_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); + break; + } + } +#if (_WIN32_IE >= 0x0300) + if(nRet > 0) // string was loaded, save it + pDispInfo->uFlags |= TTF_DI_SETITEM; +#endif // (_WIN32_IE >= 0x0300) + } + + return 0; + } + + LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) + { + LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh; + pDispInfo->szText[0] = 0; + + if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) + { + const int cchBuff = 256; + wchar_t szBuff[cchBuff]; + szBuff[0] = 0; + int nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); + for(int i = 0; i < nRet; i++) + { + if(szBuff[i] == L'\n') + { + SecureHelper::strncpyW_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); + break; + } + } +#if (_WIN32_IE >= 0x0300) + if(nRet > 0) // string was loaded, save it + pDispInfo->uFlags |= TTF_DI_SETITEM; +#endif // (_WIN32_IE >= 0x0300) + } + + return 0; + } +#endif // !_WIN32_WCE + +// Implementation - chevron menu support +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + bool PrepareChevronMenu(_ChevronMenuInfo& cmi) + { + // get rebar and toolbar + REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() }; + rbbi.fMask = RBBIM_CHILD; + BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi); + ATLASSERT(bRet); + + // assume the band is a toolbar + ATL::CWindow wnd = rbbi.hwndChild; + int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT); + if(nCount <= 0) // probably not a toolbar + return false; + + // check if it's a command bar + CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU); + cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL); + + // build a menu from hidden items + CMenuHandle menu; + bRet = menu.CreatePopupMenu(); + ATLASSERT(bRet); + RECT rcClient = { 0 }; + bRet = wnd.GetClientRect(&rcClient); + ATLASSERT(bRet); + for(int i = 0; i < nCount; i++) + { + TBBUTTON tbb = { 0 }; + bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb); + ATLASSERT(bRet); + // skip hidden buttons + if((tbb.fsState & TBSTATE_HIDDEN) != 0) + continue; + RECT rcButton = { 0 }; + bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton); + ATLASSERT(bRet); + bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0); + if(rcButton.right > rcClient.right) + { + if(tbb.fsStyle & BTNS_SEP) + { + if(menu.GetMenuItemCount() > 0) + menu.AppendMenu(MF_SEPARATOR); + } + else if(cmi.bCmdBar) + { + const int cchBuff = 200; + TCHAR szBuff[cchBuff] = { 0 }; + CMenuItemInfo mii; + mii.fMask = MIIM_TYPE | MIIM_SUBMENU; + mii.dwTypeData = szBuff; + mii.cch = cchBuff; + bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + // Note: CmdBar currently supports only drop-down items + ATLASSERT(::IsMenu(mii.hSubMenu)); + bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData); + ATLASSERT(bRet); + } + else + { + // get button's text + const int cchBuff = 200; + TCHAR szBuff[cchBuff] = { 0 }; + LPTSTR lpstrText = szBuff; + TBBUTTONINFO tbbi = { 0 }; + tbbi.cbSize = sizeof(TBBUTTONINFO); + tbbi.dwMask = TBIF_TEXT; + tbbi.pszText = szBuff; + tbbi.cchText = cchBuff; + if(wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1 || lstrlen(szBuff) == 0) + { + // no text for this button, try a resource string + lpstrText = _T(""); + int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff); + for(int n = 0; n < nRet; n++) + { + if(szBuff[n] == _T('\n')) + { + lpstrText = &szBuff[n + 1]; + break; + } + } + } + bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText); + ATLASSERT(bRet); + } + } + } + + if(menu.GetMenuItemCount() == 0) // no hidden buttons after all + { + menu.DestroyMenu(); + ::MessageBeep((UINT)-1); + return false; + } + + cmi.hMenu = menu; + return true; + } + + void DisplayChevronMenu(_ChevronMenuInfo& cmi) + { +#ifndef TPM_VERPOSANIMATION + const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag +#endif + // convert chevron rect to screen coordinates + ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; + POINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom }; + wndFrom.MapWindowPoints(NULL, &pt, 1); + RECT rc = cmi.lpnm->rc; + wndFrom.MapWindowPoints(NULL, &rc); + // set up flags and rect + UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0); + TPMPARAMS TPMParams = { 0 }; + TPMParams.cbSize = sizeof(TPMPARAMS); + TPMParams.rcExclude = rc; + // check if this window has a command bar + HWND hWndCmdBar = (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L); + if(::IsWindow(hWndCmdBar)) + { + CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams }; + ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu); + } + else + { + CMenuHandle menu = cmi.hMenu; + menu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, m_hWnd, &TPMParams); + } + } + + void CleanupChevronMenu(_ChevronMenuInfo& cmi) + { + CMenuHandle menu = cmi.hMenu; + // if menu is from a command bar, detach submenus so they are not destroyed + if(cmi.bCmdBar) + { + for(int i = menu.GetMenuItemCount() - 1; i >=0; i--) + menu.RemoveMenu(i, MF_BYPOSITION); + } + // destroy menu + menu.DestroyMenu(); + // convert chevron rect to screen coordinates + ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; + RECT rc = cmi.lpnm->rc; + wndFrom.MapWindowPoints(NULL, &rc); + // eat next message if click is on the same button + MSG msg = { 0 }; + if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt)) + ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE); + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +}; + + +template +class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits > +{ +public: + HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) + { + ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); + + dwStyle = T::GetWndStyle(dwStyle); + dwExStyle = T::GetWndExStyle(dwExStyle); + + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); + } + + HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) + { + const int cchName = 256; + TCHAR szWindowName[cchName]; + szWindowName[0] = 0; +#ifndef _WIN32_WCE + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); +#else // CE specific + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + + // This always needs to be NULL for Windows CE. + // Frame Window menus have to go onto the CommandBar. + // Use CreateSimpleCECommandBar + HMENU hMenu = NULL; +#endif // _WIN32_WCE + + T* pT = static_cast(this); + HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); + + if(hWnd != NULL) + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + return hWnd; + } + + BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; +#ifndef _WIN32_WCE + ATLASSERT(!::IsWindow(m_hWndToolBar)); + m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); + return (m_hWndToolBar != NULL); +#else // CE specific + HWND hWnd= T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID); + return (hWnd != NULL); +#endif // _WIN32_WCE + } + +#ifdef _WIN32_WCE + // CE specific variant that returns the handle of the toolbar + HWND CreateSimpleCEToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; + + return T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID); + } +#endif // _WIN32_WCE + +// message map and handlers + typedef CFrameWindowImplBase< TBase, TWinTraits > _baseClass; + + BEGIN_MSG_MAP(CFrameWindowImpl) + MESSAGE_HANDLER(WM_SIZE, OnSize) +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +#endif // !_ATL_NO_REBAR_SUPPORT + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam != SIZE_MINIMIZED) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + bHandled = FALSE; + return 1; + } + +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(FALSE); + return 0; + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) + LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; + if(!pT->PrepareChevronMenu(cmi)) + { + bHandled = FALSE; + return 1; + } + // display a popup menu with hidden items + pT->DisplayChevronMenu(cmi); + // cleanup + pT->CleanupChevronMenu(cmi); + return 0; + } +#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) +#endif // !_ATL_NO_REBAR_SUPPORT +}; + + +/////////////////////////////////////////////////////////////////////////////// +// AtlCreateSimpleToolBar - helper for creating simple toolbars + +#ifndef _WIN32_WCE + +inline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, + DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) +{ + return CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID); +} + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMDIWindow + +#ifndef _WIN32_WCE + +#ifndef _WTL_MDIWINDOWMENU_TEXT +#define _WTL_MDIWINDOWMENU_TEXT _T("&Window") +#endif + +class CMDIWindow : public ATL::CWindow +{ +public: +// Data members + HWND m_hWndMDIClient; + HMENU m_hMenu; + +// Constructors + CMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL) + { } + + CMDIWindow& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// Operations + HWND MDIGetActive(BOOL* lpbMaximized = NULL) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized); + } + + void MDIActivate(HWND hWndChildToActivate) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToActivate)); + ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0); + } + + void MDINext(HWND hWndChild, BOOL bPrevious = FALSE) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild)); + ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious); + } + + void MDIMaximize(HWND hWndChildToMaximize) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToMaximize)); + ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0); + } + + void MDIRestore(HWND hWndChildToRestore) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToRestore)); + ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0); + } + + void MDIDestroy(HWND hWndChildToDestroy) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ATLASSERT(::IsWindow(hWndChildToDestroy)); + ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0); + } + + BOOL MDICascade(UINT uFlags = 0) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0); + } + + BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0); + } + + void MDIIconArrange() + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0); + } + + HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow) + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow); + } + + HMENU MDIRefreshMenu() + { + ATLASSERT(::IsWindow(m_hWndMDIClient)); + return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0); + } + +// Additional operations + static HMENU GetStandardWindowMenu(HMENU hMenu) + { + int nCount = ::GetMenuItemCount(hMenu); + if(nCount == -1) + return NULL; + int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION); + if(nLen == 0) + return NULL; + CTempBuffer buff; + LPTSTR lpszText = buff.Allocate(nLen + 1); + if(lpszText == NULL) + return NULL; + if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen) + return NULL; + if(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0) + return NULL; + return ::GetSubMenu(hMenu, nCount - 2); + } + + void SetMDIFrameMenu() + { + HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu); + MDISetMenu(m_hMenu, hWindowMenu); + MDIRefreshMenu(); + ::DrawMenuBar(GetMDIFrame()); + } + + HWND GetMDIFrame() const + { + return ::GetParent(m_hWndMDIClient); + } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMDIFrameWindowImpl + +#ifndef _WIN32_WCE + +// MDI child command chaining macro (only for MDI frame windows) +#define CHAIN_MDI_CHILD_COMMANDS() \ + if(uMsg == WM_COMMAND) \ + { \ + HWND hWndChild = MDIGetActive(); \ + if(hWndChild != NULL) \ + ::SendMessage(hWndChild, uMsg, wParam, lParam); \ + } + +template +class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase +{ +public: + HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) + { + m_hMenu = hMenu; + ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); + + dwStyle = T::GetWndStyle(dwStyle); + dwExStyle = T::GetWndExStyle(dwExStyle); + + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + return CFrameWindowImplBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); + } + + HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) + { + const int cchName = 256; + TCHAR szWindowName[cchName]; + szWindowName[0] = 0; + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + T* pT = static_cast(this); + HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); + + if(hWnd != NULL) + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + return hWnd; + } + + BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; + m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); + return (m_hWndToolBar != NULL); + } + + virtual WNDPROC GetWindowProc() + { + return MDIFrameWindowProc; + } + + static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd; + // set a ptr to this message and save the old value +#if (_ATL_VER >= 0x0700) + ATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam); + const ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg; +#else // !(_ATL_VER >= 0x0700) + MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } }; + const MSG* pOldMsg = pThis->m_pCurrentMsg; +#endif // !(_ATL_VER >= 0x0700) + pThis->m_pCurrentMsg = &msg; + // pass to the message map to process + LRESULT lRes = 0; + BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0); + // restore saved value for the current message + ATLASSERT(pThis->m_pCurrentMsg == &msg); + pThis->m_pCurrentMsg = pOldMsg; + // do the default processing if message was not handled + if(!bRet) + { + if(uMsg != WM_NCDESTROY) + lRes = pThis->DefWindowProc(uMsg, wParam, lParam); + else + { + // unsubclass, if needed + LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC); + lRes = pThis->DefWindowProc(uMsg, wParam, lParam); + if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc) + ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc); +#if (_ATL_VER >= 0x0700) + // mark window as destryed + pThis->m_dwState |= WINSTATE_DESTROYED; +#else // !(_ATL_VER >= 0x0700) + // clear out window handle + HWND hWnd = pThis->m_hWnd; + pThis->m_hWnd = NULL; + // clean up after window is destroyed + pThis->OnFinalMessage(hWnd); +#endif // !(_ATL_VER >= 0x0700) + } + } +#if (_ATL_VER >= 0x0700) + if(pThis->m_dwState & WINSTATE_DESTROYED && pThis->m_pCurrentMsg == NULL) + { + // clear out window handle + HWND hWnd = pThis->m_hWnd; + pThis->m_hWnd = NULL; + pThis->m_dwState &= ~WINSTATE_DESTROYED; + // clean up after window is destroyed + pThis->OnFinalMessage(hWnd); + } +#endif // (_ATL_VER >= 0x0700) + return lRes; + } + + // Overriden to call DefWindowProc which uses DefFrameProc + LRESULT DefWindowProc() + { + const MSG* pMsg = m_pCurrentMsg; + LRESULT lRes = 0; + if (pMsg != NULL) + lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam); + return lRes; + } + + LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + return ::DefFrameProc(m_hWnd, m_hWndMDIClient, uMsg, wParam, lParam); + } + + BOOL PreTranslateMessage(MSG* pMsg) + { + if(CFrameWindowImplBase::PreTranslateMessage(pMsg)) + return TRUE; + return ::TranslateMDISysAccel(m_hWndMDIClient, pMsg); + } + + HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD) + { + DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES; + DWORD dwExStyle = WS_EX_CLIENTEDGE; + + CLIENTCREATESTRUCT ccs = { 0 }; + ccs.hWindowMenu = hWindowMenu; + ccs.idFirstChild = nFirstChildID; + + if((GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0) + { + // parent MDI frame's scroll styles move to the MDICLIENT + dwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL)); + + // fast way to turn off the scrollbar bits (without a resize) + ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED); + } + + // Create MDICLIENT window + m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL, + dwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)LongToHandle(nID), + ModuleHelper::GetModuleInstance(), (LPVOID)&ccs); + if (m_hWndClient == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n")); + return NULL; + } + + // Move it to the top of z-order + ::BringWindowToTop(m_hWndClient); + + // set as MDI client window + m_hWndMDIClient = m_hWndClient; + + // update to proper size + T* pT = static_cast(this); + pT->UpdateLayout(); + + return m_hWndClient; + } + + typedef CFrameWindowImplBase _baseClass; + + BEGIN_MSG_MAP(CMDIFrameWindowImpl) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu) +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(wParam != SIZE_MINIMIZED) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + // message must be handled, otherwise DefFrameProc would resize the client again + return 0; + } + + LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + // don't allow CFrameWindowImplBase to handle this one + return DefWindowProc(uMsg, wParam, lParam); + } + + LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + SetMDIFrameMenu(); + return 0; + } + +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(FALSE); + return 0; + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; + if(!pT->PrepareChevronMenu(cmi)) + { + bHandled = FALSE; + return 1; + } + // display a popup menu with hidden items + pT->DisplayChevronMenu(cmi); + // cleanup + pT->CleanupChevronMenu(cmi); + return 0; + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMDIChildWindowImpl + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase +{ +public: + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + UINT nMenuID = 0, LPVOID lpCreateParam = NULL) + { + ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); + + if(nMenuID != 0) + m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID)); + + dwStyle = T::GetWndStyle(dwStyle); + dwExStyle = T::GetWndExStyle(dwExStyle); + + dwExStyle |= WS_EX_MDICHILD; // force this one + m_pfnSuperWindowProc = ::DefMDIChildProc; + m_hWndMDIClient = hWndParent; + ATLASSERT(::IsWindow(m_hWndMDIClient)); + + if(rect.m_lpRect == NULL) + rect.m_lpRect = &TBase::rcDefault; + + // If the currently active MDI child is maximized, we want to create this one maximized too + ATL::CWindow wndParent = hWndParent; + BOOL bMaximized = FALSE; + wndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); + if(bMaximized) + wndParent.SetRedraw(FALSE); + + HWND hWnd = CFrameWindowImplBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam); + + if(bMaximized) + { + // Maximize and redraw everything + if(hWnd != NULL) + MDIMaximize(hWnd); + wndParent.SetRedraw(TRUE); + wndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + ::SetFocus(GetMDIFrame()); // focus will be set back to this window + } + else if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus())) + { + ::SetFocus(hWnd); + } + + return hWnd; + } + + HWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) + { + const int cchName = 256; + TCHAR szWindowName[cchName]; + szWindowName[0] = 0; + if(lpcstrWindowName == NULL) + { + ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); + lpcstrWindowName = szWindowName; + } + + T* pT = static_cast(this); + HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam); + + if(hWnd != NULL) + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); + + return hWnd; + } + + BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) + { + ATLASSERT(!::IsWindow(m_hWndToolBar)); + if(nResourceID == 0) + nResourceID = T::GetWndClassInfo().m_uCommonResourceID; + m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); + return (m_hWndToolBar != NULL); + } + + BOOL UpdateClientEdge(LPRECT lpRect = NULL) + { + // only adjust for active MDI child window + HWND hWndChild = MDIGetActive(); + if(hWndChild != NULL && hWndChild != m_hWnd) + return FALSE; + + // need to adjust the client edge style as max/restore happens + DWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE); + DWORD dwNewStyle = dwStyle; + if(hWndChild != NULL && ((GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((GetStyle() & WS_MAXIMIZE) != 0)) + dwNewStyle &= ~(WS_EX_CLIENTEDGE); + else + dwNewStyle |= WS_EX_CLIENTEDGE; + + if(dwStyle != dwNewStyle) + { + // SetWindowPos will not move invalid bits + ::RedrawWindow(m_hWndMDIClient, NULL, NULL, + RDW_INVALIDATE | RDW_ALLCHILDREN); + // remove/add WS_EX_CLIENTEDGE to MDI client area + ::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle); + ::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | + SWP_NOZORDER | SWP_NOCOPYBITS); + + // return new client area + if (lpRect != NULL) + ::GetClientRect(m_hWndMDIClient, lpRect); + + return TRUE; + } + + return FALSE; + } + + typedef CFrameWindowImplBase _baseClass; + BEGIN_MSG_MAP(CMDIChildWindowImpl) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged) + MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) + MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) + MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) +#endif // (_WIN32_IE >= 0x0400) +#if (_WIN32_IE >= 0x0500) + NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT + CHAIN_MSG_MAP(_baseClass) + END_MSG_MAP() + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + DefWindowProc(uMsg, wParam, lParam); // needed for MDI children + if(wParam != SIZE_MINIMIZED) + { + T* pT = static_cast(this); + pT->UpdateLayout(); + } + return 0; + } + + LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + // update MDI client edge and adjust MDI child rect + LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam; + + if(!(lpWndPos->flags & SWP_NOSIZE)) + { + RECT rectClient; + if(UpdateClientEdge(&rectClient) && ((GetStyle() & WS_MAXIMIZE) != 0)) + { + ::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle()); + lpWndPos->x = rectClient.left; + lpWndPos->y = rectClient.top; + lpWndPos->cx = rectClient.right - rectClient.left; + lpWndPos->cy = rectClient.bottom - rectClient.top; + } + } + + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + LRESULT lRes = DefWindowProc(uMsg, wParam, lParam); + + // Activate this MDI window if needed + if(lRes == MA_ACTIVATE || lRes == MA_ACTIVATEANDEAT) + { + if(MDIGetActive() != m_hWnd) + MDIActivate(m_hWnd); + } + + return lRes; + } + + LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + return ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam); + } + + LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if((HWND)lParam == m_hWnd && m_hMenu != NULL) + SetMDIFrameMenu(); + else if((HWND)lParam == NULL) + ::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0); + + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_hMenu != NULL) + { + ::DestroyMenu(m_hMenu); + m_hMenu = NULL; + } + UpdateClientEdge(); + bHandled = FALSE; + return 1; + } + +#ifndef _ATL_NO_REBAR_SUPPORT +#if (_WIN32_IE >= 0x0400) + LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->UpdateLayout(FALSE); + return 0; + } +#endif // (_WIN32_IE >= 0x0400) + +#if (_WIN32_IE >= 0x0500) + LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + T* pT = static_cast(this); + _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; + if(!pT->PrepareChevronMenu(cmi)) + { + bHandled = FALSE; + return 1; + } + // display a popup menu with hidden items + pT->DisplayChevronMenu(cmi); + // cleanup + pT->CleanupChevronMenu(cmi); + return 0; + } +#endif // (_WIN32_IE >= 0x0500) +#endif // !_ATL_NO_REBAR_SUPPORT +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// COwnerDraw - MI class for owner-draw support + +template +class COwnerDraw +{ +public: +#if (_ATL_VER < 0x0700) + BOOL m_bHandledOD; + + BOOL IsMsgHandled() const + { + return m_bHandledOD; + } + void SetMsgHandled(BOOL bHandled) + { + m_bHandledOD = bHandled; + } +#endif // (_ATL_VER < 0x0700) + +// Message map and handlers + BEGIN_MSG_MAP(COwnerDraw< T >) + MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) + MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem) + MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem) + MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem) + ALT_MSG_MAP(1) + MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem) + MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem) + MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem) + MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem) + END_MSG_MAP() + + LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + pT->DrawItem((LPDRAWITEMSTRUCT)lParam); + bHandled = pT->IsMsgHandled(); + return (LRESULT)TRUE; + } + + LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam); + bHandled = pT->IsMsgHandled(); + return (LRESULT)TRUE; + } + + LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + bHandled = pT->IsMsgHandled(); + return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam); + } + + LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->SetMsgHandled(TRUE); + pT->DeleteItem((LPDELETEITEMSTRUCT)lParam); + bHandled = pT->IsMsgHandled(); + return (LRESULT)TRUE; + } + +// Overrideables + void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/) + { + // must be implemented + ATLASSERT(FALSE); + } + + void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) + { + if(lpMeasureItemStruct->CtlType != ODT_MENU) + { + // return default height for a system font + T* pT = static_cast(this); + HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID); + CClientDC dc(hWnd); + TEXTMETRIC tm = { 0 }; + dc.GetTextMetrics(&tm); + + lpMeasureItemStruct->itemHeight = tm.tmHeight; + } + else + lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU); + } + + int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/) + { + // all items are equal + return 0; + } + + void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/) + { + // default - nothing + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Update UI macros + +// these build the Update UI map inside a class definition +#define BEGIN_UPDATE_UI_MAP(thisClass) \ + static const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \ + { \ + static const _AtlUpdateUIMap theMap[] = \ + { + +#define UPDATE_ELEMENT(nID, wType) \ + { nID, wType }, + +#define END_UPDATE_UI_MAP() \ + { (WORD)-1, 0 } \ + }; \ + return theMap; \ + } + +/////////////////////////////////////////////////////////////////////////////// +// CUpdateUI - manages UI elements updating + +class CUpdateUIBase +{ +public: + // constants + enum + { + // UI element type + UPDUI_MENUPOPUP = 0x0001, + UPDUI_MENUBAR = 0x0002, + UPDUI_CHILDWINDOW = 0x0004, + UPDUI_TOOLBAR = 0x0008, + UPDUI_STATUSBAR = 0x0010, + // state + UPDUI_ENABLED = 0x0000, + UPDUI_DISABLED = 0x0100, + UPDUI_CHECKED = 0x0200, + UPDUI_CHECKED2 = 0x0400, + UPDUI_RADIO = 0x0800, + UPDUI_DEFAULT = 0x1000, + UPDUI_TEXT = 0x2000, + // internal state + UPDUI_CLEARDEFAULT = 0x4000, + }; + + // element data + struct _AtlUpdateUIElement + { + HWND m_hWnd; + WORD m_wType; + + bool operator ==(const _AtlUpdateUIElement& e) const + { return (m_hWnd == e.m_hWnd && m_wType == e.m_wType); } + }; + + // map data + struct _AtlUpdateUIMap + { + WORD m_nID; + WORD m_wType; + + bool operator ==(const _AtlUpdateUIMap& e) const + { return (m_nID == e.m_nID && m_wType == e.m_wType); } + }; + + // instance data + struct _AtlUpdateUIData + { + WORD m_wState; + union + { + void* m_lpData; + LPTSTR m_lpstrText; + }; + + bool operator ==(const _AtlUpdateUIData& e) const + { return (m_wState == e.m_wState && m_lpData == e.m_lpData); } + }; + + ATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data + const _AtlUpdateUIMap* m_pUIMap; // static UI data + _AtlUpdateUIData* m_pUIData; // instance UI data + WORD m_wDirtyType; // global dirty flag + + bool m_bBlockAccelerators; + + +// Constructor, destructor + CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false) + { } + + ~CUpdateUIBase() + { + if(m_pUIMap != NULL && m_pUIData != NULL) + { + const _AtlUpdateUIMap* pUIMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + while(pUIMap->m_nID != (WORD)-1) + { + if(pUIData->m_wState & UPDUI_TEXT) + delete [] pUIData->m_lpstrText; + pUIMap++; + pUIData++; + } + delete [] m_pUIData; + } + } + +// Check for disabled commands + bool UIGetBlockAccelerators() const + { + return m_bBlockAccelerators; + } + + bool UISetBlockAccelerators(bool bBlock) + { + bool bOld = m_bBlockAccelerators; + m_bBlockAccelerators = bBlock; + return bOld; + } + +// Add elements + BOOL UIAddMenuBar(HWND hWnd) // menu bar (main menu) + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_MENUBAR; + return m_UIElements.Add(e); + } + + BOOL UIAddToolBar(HWND hWnd) // toolbar + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_TOOLBAR; + return m_UIElements.Add(e); + } + + BOOL UIAddStatusBar(HWND hWnd) // status bar + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_STATUSBAR; + return m_UIElements.Add(e); + } + + BOOL UIAddChildWindowContainer(HWND hWnd) // child window + { + if(hWnd == NULL) + return FALSE; + _AtlUpdateUIElement e; + e.m_hWnd = hWnd; + e.m_wType = UPDUI_CHILDWINDOW; + return m_UIElements.Add(e); + } + +// Message map for popup menu updates and accelerator blocking + BEGIN_MSG_MAP(CUpdateUIBase) + MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) + MESSAGE_HANDLER(WM_COMMAND, OnCommand) + END_MSG_MAP() + + LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; + HMENU hMenu = (HMENU)wParam; + if(hMenu == NULL) + return 1; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return 1; + const _AtlUpdateUIMap* pMap = m_pUIMap; + while(pMap->m_nID != (WORD)-1) + { + if(pMap->m_wType & UPDUI_MENUPOPUP) + UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); + pMap++; + pUIData++; + } + return 0; + } + + LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; + if(m_bBlockAccelerators && HIWORD(wParam) == 1) // accelerators only + { + int nID = LOWORD(wParam); + if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED) + { + ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID); + bHandled = TRUE; // eat the command, UI item is disabled + } + } + return 0; + } + +// methods for setting UI element state + BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(bEnable) + { + if(pUIData->m_wState & UPDUI_DISABLED) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_DISABLED; + } + } + else + { + if(!(pUIData->m_wState & UPDUI_DISABLED)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_DISABLED; + } + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + switch(nCheck) + { + case 0: + if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2); + } + break; + case 1: + if(!(pUIData->m_wState & UPDUI_CHECKED)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_CHECKED2; + pUIData->m_wState |= UPDUI_CHECKED; + } + break; + case 2: + if(!(pUIData->m_wState & UPDUI_CHECKED2)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_CHECKED; + pUIData->m_wState |= UPDUI_CHECKED2; + } + break; + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + // variant that supports bool (checked/not-checked, no intermediate state) + BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE) + { + return UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate); + } + + BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(bRadio) + { + if(!(pUIData->m_wState & UPDUI_RADIO)) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_RADIO; + } + } + else + { + if(pUIData->m_wState & UPDUI_RADIO) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_RADIO; + } + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + if(lpstrText == NULL) + lpstrText = _T(""); + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(pUIData->m_lpstrText == NULL || lstrcmp(pUIData->m_lpstrText, lpstrText)) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + int nStrLen = lstrlen(lpstrText); + ATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]); + if(pUIData->m_lpstrText == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("UISetText - memory allocation failed\n")); + break; + } + SecureHelper::strcpy_x(pUIData->m_lpstrText, nStrLen + 1, lpstrText); + pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); + } + + if(bForceUpdate) + pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + + BOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + if(bDefault) + { + if((pUIData->m_wState & UPDUI_DEFAULT) == 0) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState |= UPDUI_DEFAULT; + } + } + else + { + if((pUIData->m_wState & UPDUI_DEFAULT) != 0) + { + pUIData->m_wState |= pMap->m_wType; + pUIData->m_wState &= ~UPDUI_DEFAULT; + pUIData->m_wState |= UPDUI_CLEARDEFAULT; + } + } + + if(bForceUpdate) + pUIData->m_wState |= pMap->m_wType; + if(pUIData->m_wState & pMap->m_wType) + m_wDirtyType |= pMap->m_wType; + + break; // found + } + } + + return TRUE; + } + +// methods for complete state set/get + BOOL UISetState(int nID, DWORD dwState) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + { + pUIData->m_wState = (WORD)(dwState | pMap->m_wType); + m_wDirtyType |= pMap->m_wType; + break; // found + } + } + return TRUE; + } + + DWORD UIGetState(int nID) + { + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return 0; + for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) + { + if(nID == (int)pMap->m_nID) + return pUIData->m_wState; + } + return 0; + } + +// methods for updating UI +#ifndef _WIN32_WCE + BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE) + { + if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_MENUBAR) + { + HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd); + if(hMenu != NULL && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR)) + UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); + } + if(bMainMenu) + ::DrawMenuBar(m_UIElements[i].m_hWnd); + } + pMap++; + pUIData->m_wState &= ~UPDUI_MENUBAR; + if(pUIData->m_wState & UPDUI_TEXT) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + pUIData->m_wState &= ~UPDUI_TEXT; + } + pUIData++; + } + + m_wDirtyType &= ~UPDUI_MENUBAR; + return TRUE; + } +#endif // !_WIN32_WCE + + BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_TOOLBAR) + { + if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR)) + UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); + } + } + pMap++; + pUIData->m_wState &= ~UPDUI_TOOLBAR; + pUIData++; + } + + m_wDirtyType &= ~UPDUI_TOOLBAR; + return TRUE; + } + + BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_STATUSBAR) + { + if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR)) + UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); + } + } + pMap++; + pUIData->m_wState &= ~UPDUI_STATUSBAR; + if(pUIData->m_wState & UPDUI_TEXT) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + pUIData->m_wState &= ~UPDUI_TEXT; + } + pUIData++; + } + + m_wDirtyType &= ~UPDUI_STATUSBAR; + return TRUE; + } + + BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE) + { + if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate) + return TRUE; + + const _AtlUpdateUIMap* pMap = m_pUIMap; + _AtlUpdateUIData* pUIData = m_pUIData; + if(pUIData == NULL) + return FALSE; + + while(pMap->m_nID != (WORD)-1) + { + for(int i = 0; i < m_UIElements.GetSize(); i++) + { + if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW) + { + if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW)) + UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); + } + } + pMap++; + pUIData->m_wState &= ~UPDUI_CHILDWINDOW; + if(pUIData->m_wState & UPDUI_TEXT) + { + delete [] pUIData->m_lpstrText; + pUIData->m_lpstrText = NULL; + pUIData->m_wState &= ~UPDUI_TEXT; + } + pUIData++; + } + + m_wDirtyType &= ~UPDUI_CHILDWINDOW; + return TRUE; + } + +// internal element specific methods + static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu) + { +#ifndef _WIN32_WCE + if((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0) + { + ::SetMenuDefaultItem(hMenu, (UINT)-1, 0); + pUIData->m_wState &= ~UPDUI_CLEARDEFAULT; + } +#endif // !_WIN32_WCE + + CMenuItemInfo mii; + mii.fMask = MIIM_STATE; + mii.wID = nID; + +#ifndef _WIN32_WCE + if((pUIData->m_wState & UPDUI_DISABLED) != 0) + mii.fState |= MFS_DISABLED | MFS_GRAYED; + else + mii.fState |= MFS_ENABLED; + + if((pUIData->m_wState & UPDUI_CHECKED) != 0) + mii.fState |= MFS_CHECKED; + else + mii.fState |= MFS_UNCHECKED; + + if((pUIData->m_wState & UPDUI_DEFAULT) != 0) + mii.fState |= MFS_DEFAULT; +#else // CE specific + // ::SetMenuItemInfo() can't disable or check menu items + // on Windows CE, so we have to do that directly + UINT uEnable = MF_BYCOMMAND; + if((pUIData->m_wState & UPDUI_DISABLED) != 0) + uEnable |= MF_GRAYED; + else + uEnable |= MF_ENABLED; + ::EnableMenuItem(hMenu, nID, uEnable); + + UINT uCheck = MF_BYCOMMAND; + if((pUIData->m_wState & UPDUI_CHECKED) != 0) + uCheck |= MF_CHECKED; + else + uCheck |= MF_UNCHECKED; + ::CheckMenuItem(hMenu, nID, uCheck); +#endif // _WIN32_WCE + + if((pUIData->m_wState & UPDUI_TEXT) != 0) + { + CMenuItemInfo miiNow; + miiNow.fMask = MIIM_TYPE; + miiNow.wID = nID; + if(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow)) + { + mii.fMask |= MIIM_TYPE; + // MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING +#ifndef _WIN32_WCE + mii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING; +#else // CE specific + mii.fType |= (miiNow.fType & ~(MFT_SEPARATOR)) | MFT_STRING; +#endif // _WIN32_WCE + mii.dwTypeData = pUIData->m_lpstrText; + } + } + + ::SetMenuItemInfo(hMenu, nID, FALSE, &mii); + } + + static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar) + { + // Note: only handles enabled/disabled, checked state, and radio (press) + ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); + ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE); + ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE); + ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE); + } + + static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar) + { + // Note: only handles text + if(pUIData->m_wState & UPDUI_TEXT) + ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText); + } + + static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd) + { + HWND hChild = ::GetDlgItem(hWnd, nID); + + ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); + // for check and radio, assume that window is a button + int nCheck = BST_UNCHECKED; + if(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO) + nCheck = BST_CHECKED; + else if(pUIData->m_wState & UPDUI_CHECKED2) + nCheck = BST_INDETERMINATE; + ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L); + if(pUIData->m_wState & UPDUI_DEFAULT) + { + DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L); + if(HIWORD(dwRet) == DC_HASDEFID) + { + HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet)); + // remove BS_DEFPUSHBUTTON + ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); + } + ::SendMessage(hWnd, DM_SETDEFID, nID, 0L); + } + if(pUIData->m_wState & UPDUI_TEXT) + ::SetWindowText(hChild, pUIData->m_lpstrText); + } +}; + +template +class CUpdateUI : public CUpdateUIBase +{ +public: + CUpdateUI() + { + T* pT = static_cast(this); + pT; + const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); + m_pUIMap = pMap; + ATLASSERT(m_pUIMap != NULL); + int nCount; + for(nCount = 1; pMap->m_nID != (WORD)-1; nCount++) + pMap++; + + // check for duplicates (debug only) +#ifdef _DEBUG + for(int i = 0; i < nCount; i++) + { + for(int j = 0; j < nCount; j++) + { + // shouldn't have duplicates in the update UI map + if(i != j) + ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID); + } + } +#endif // _DEBUG + + ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]); + ATLASSERT(m_pUIData != NULL); + + if(m_pUIData != NULL) + memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDynamicUpdateUI - allows update elements to dynamically added and removed +// in addition to a static update UI map + +template +class CDynamicUpdateUI : public CUpdateUIBase +{ +public: +// Data members + ATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap; // copy of the static UI data + ATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData; // instance UI data + +// Constructor/destructor + CDynamicUpdateUI() + { + T* pT = static_cast(this); + pT; + const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); + ATLASSERT(pMap != NULL); + + for(;;) + { + BOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap); + ATLASSERT(bRet); + + if(bRet != FALSE) + { + _AtlUpdateUIData data = { 0, NULL }; + bRet = m_arrUIData.Add(data); + ATLASSERT(bRet); + } + + if(pMap->m_nID == (WORD)-1) + break; + + pMap++; + } + + ATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize()); + +#ifdef _DEBUG + // check for duplicates (debug only) + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + for(int j = 0; j < m_arrUIMap.GetSize(); j++) + { + // shouldn't have duplicates in the update UI map + if(i != j) + ATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID); + } + } +#endif // _DEBUG + + // Set internal data pointers to point to the new data arrays + m_pUIMap = m_arrUIMap.m_aT; + m_pUIData = m_arrUIData.m_aT; + } + + ~CDynamicUpdateUI() + { + for(int i = 0; i < m_arrUIData.GetSize(); i++) + { + if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0) + delete [] m_arrUIData[i].m_lpstrText; + } + + // Reset internal data pointers (memory will be released by CSimpleArray d-tor) + m_pUIMap = NULL; + m_pUIData = NULL; + } + +// Methods for dynamically adding and removing update elements + bool UIAddUpdateElement(WORD nID, WORD wType) + { + // check for duplicates + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + // shouldn't have duplicates in the update UI map + ATLASSERT(m_arrUIMap[i].m_nID != nID); + if(m_arrUIMap[i].m_nID == nID) + return false; + } + + bool bRetVal = false; + + // Add new end element + _AtlUpdateUIMap uumEnd = { (WORD)-1, 0 }; + BOOL bRet = m_arrUIMap.Add(uumEnd); + ATLASSERT(bRet); + + if(bRet != FALSE) + { + _AtlUpdateUIData uud = { 0, NULL }; + bRet = m_arrUIData.Add(uud); + ATLASSERT(bRet); + + // Set new data to the previous end element + if(bRet != FALSE) + { + int nSize = m_arrUIMap.GetSize(); + _AtlUpdateUIMap uum = { nID, wType }; + m_arrUIMap.SetAtIndex(nSize - 2, uum); + m_arrUIData.SetAtIndex(nSize - 2, uud); + + // Set internal data pointers again, just in case that memory moved + m_pUIMap = m_arrUIMap.m_aT; + m_pUIData = m_arrUIData.m_aT; + + bRetVal = true; + } + } + + return bRetVal; + } + + bool UIRemoveUpdateElement(WORD nID) + { + bool bRetVal = false; + + for(int i = 0; i < m_arrUIMap.GetSize(); i++) + { + if(m_arrUIMap[i].m_nID == nID) + { + BOOL bRet = m_arrUIMap.RemoveAt(i); + ATLASSERT(bRet); + bRet = m_arrUIData.RemoveAt(i); + ATLASSERT(bRet); + + bRetVal = true; + break; + } + } + + return bRetVal; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDialogResize - provides support for resizing dialog controls +// (works for any window that has child controls) + +// Put CDialogResize in the list of base classes for a dialog (or even plain window), +// then implement DLGRESIZE map by specifying controls and groups of control +// and using DLSZ_* values to specify how are they supposed to be resized. +// +// Notes: +// - Resizeable border (WS_THICKFRAME style) should be set in the dialog template +// for top level dialogs (popup or overlapped), so that users can resize the dialog. +// - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X, +// DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined. +// - Order of controls is important - group controls are resized and moved based +// on the position of the previous control in a group. + +// dialog resize map macros +#define BEGIN_DLGRESIZE_MAP(thisClass) \ + static const _AtlDlgResizeMap* GetDlgResizeMap() \ + { \ + static const _AtlDlgResizeMap theMap[] = \ + { + +#define END_DLGRESIZE_MAP() \ + { -1, 0 }, \ + }; \ + return theMap; \ + } + +#define DLGRESIZE_CONTROL(id, flags) \ + { id, flags }, + +#define BEGIN_DLGRESIZE_GROUP() \ + { -1, _DLSZ_BEGIN_GROUP }, + +#define END_DLGRESIZE_GROUP() \ + { -1, _DLSZ_END_GROUP }, + + +template +class CDialogResize +{ +public: +// Data declarations and members + enum + { + DLSZ_SIZE_X = 0x00000001, + DLSZ_SIZE_Y = 0x00000002, + DLSZ_MOVE_X = 0x00000004, + DLSZ_MOVE_Y = 0x00000008, + DLSZ_REPAINT = 0x00000010, + DLSZ_CENTER_X = 0x00000020, + DLSZ_CENTER_Y = 0x00000040, + + // internal use only + _DLSZ_BEGIN_GROUP = 0x00001000, + _DLSZ_END_GROUP = 0x00002000, + _DLSZ_GRIPPER = 0x00004000 + }; + + struct _AtlDlgResizeMap + { + int m_nCtlID; + DWORD m_dwResizeFlags; + }; + + struct _AtlDlgResizeData + { + int m_nCtlID; + DWORD m_dwResizeFlags; + RECT m_rect; + + int GetGroupCount() const + { + return (int)LOBYTE(HIWORD(m_dwResizeFlags)); + } + + void SetGroupCount(int nCount) + { + ATLASSERT(nCount > 0 && nCount < 256); + DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0)); + m_dwResizeFlags &= 0xFF00FFFF; + m_dwResizeFlags |= dwCount; + } + + bool operator ==(const _AtlDlgResizeData& r) const + { return (m_nCtlID == r.m_nCtlID && m_dwResizeFlags == r.m_dwResizeFlags); } + }; + + ATL::CSimpleArray<_AtlDlgResizeData> m_arrData; + SIZE m_sizeDialog; + POINT m_ptMinTrackSize; + bool m_bGripper; + + +// Constructor + CDialogResize() : m_bGripper(false) + { + m_sizeDialog.cx = 0; + m_sizeDialog.cy = 0; + m_ptMinTrackSize.x = -1; + m_ptMinTrackSize.y = -1; + } + +// Operations + void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + DWORD dwStyle = pT->GetStyle(); + +#ifdef _DEBUG + // Debug only: Check if top level dialogs have a resizeable border. + if(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0)) + ATLTRACE2(atlTraceUI, 0, _T("DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\n")); +#endif // _DEBUG + + // Force specified styles (default WS_CLIPCHILDREN reduces flicker) + if((dwStyle & dwForceStyle) != dwForceStyle) + pT->ModifyStyle(0, dwForceStyle); + + // Adding this style removes an empty icon that dialogs with WS_THICKFRAME have. + // Setting icon to NULL is required when XP themes are active. + // Note: This will not prevent adding an icon for the dialog using SetIcon() + if((dwStyle & WS_CHILD) == 0) + { + pT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME); + if(pT->GetIcon(FALSE) == NULL) + pT->SetIcon(NULL, FALSE); + } + + // Cleanup in case of multiple initialization + // block: first check for the gripper control, destroy it if needed + { + ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); + if(wndGripper.IsWindow() && m_arrData.GetSize() > 0 && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0) + wndGripper.DestroyWindow(); + } + // clear out everything else + m_arrData.RemoveAll(); + m_sizeDialog.cx = 0; + m_sizeDialog.cy = 0; + m_ptMinTrackSize.x = -1; + m_ptMinTrackSize.y = -1; + + // Get initial dialog client size + RECT rectDlg = { 0 }; + pT->GetClientRect(&rectDlg); + m_sizeDialog.cx = rectDlg.right; + m_sizeDialog.cy = rectDlg.bottom; + +#ifndef _WIN32_WCE + // Create gripper if requested + m_bGripper = false; + if(bAddGripper) + { + // shouldn't exist already + ATLASSERT(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR))); + if(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR))) + { + ATL::CWindow wndGripper; + wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rectDlg, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR); + ATLASSERT(wndGripper.IsWindow()); + if(wndGripper.IsWindow()) + { + m_bGripper = true; + RECT rectCtl = { 0 }; + wndGripper.GetWindowRect(&rectCtl); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); + _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; + m_arrData.Add(data); + } + } + } +#else // CE specific + bAddGripper; // avoid level 4 warning +#endif // _WIN32_WCE + + // Get min track position if requested + if(bUseMinTrackSize) + { + if((dwStyle & WS_CHILD) != 0) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + m_ptMinTrackSize.x = rect.right - rect.left; + m_ptMinTrackSize.y = rect.bottom - rect.top; + } + else + { + RECT rect = { 0 }; + pT->GetWindowRect(&rect); + m_ptMinTrackSize.x = rect.right - rect.left; + m_ptMinTrackSize.y = rect.bottom - rect.top; + } + } + + // Walk the map and initialize data + const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap(); + ATLASSERT(pMap != NULL); + int nGroupStart = -1; + for(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++) + { + if(pMap->m_nCtlID == -1) + { + switch(pMap->m_dwResizeFlags) + { + case _DLSZ_BEGIN_GROUP: + ATLASSERT(nGroupStart == -1); + nGroupStart = m_arrData.GetSize(); + break; + case _DLSZ_END_GROUP: + { + ATLASSERT(nGroupStart != -1); + int nGroupCount = m_arrData.GetSize() - nGroupStart; + m_arrData[nGroupStart].SetGroupCount(nGroupCount); + nGroupStart = -1; + } + break; + default: + ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry")); + break; + } + } + else + { + // this ID conflicts with the default gripper one + ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE); + + ATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID); + ATLASSERT(ctl.IsWindow()); + RECT rectCtl = { 0 }; + ctl.GetWindowRect(&rectCtl); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); + + DWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0; + _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; + m_arrData.Add(data); + } + } + ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map")); + } + + void DlgResize_UpdateLayout(int cxWidth, int cyHeight) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + // Restrict minimum size if requested + if(((pT->GetStyle() & WS_CHILD) != 0) && m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1) + { + if(cxWidth < m_ptMinTrackSize.x) + cxWidth = m_ptMinTrackSize.x; + if(cyHeight < m_ptMinTrackSize.y) + cyHeight = m_ptMinTrackSize.y; + } + + BOOL bVisible = pT->IsWindowVisible(); + if(bVisible) + pT->SetRedraw(FALSE); + + for(int i = 0; i < m_arrData.GetSize(); i++) + { + if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group + { + int nGroupCount = m_arrData[i].GetGroupCount(); + ATLASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize()); + RECT rectGroup = m_arrData[i].m_rect; + + int j = 1; + for(j = 1; j < nGroupCount; j++) + { + rectGroup.left = min(rectGroup.left, m_arrData[i + j].m_rect.left); + rectGroup.top = min(rectGroup.top, m_arrData[i + j].m_rect.top); + rectGroup.right = max(rectGroup.right, m_arrData[i + j].m_rect.right); + rectGroup.bottom = max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom); + } + + for(j = 0; j < nGroupCount; j++) + { + _AtlDlgResizeData* pDataPrev = NULL; + if(j > 0) + pDataPrev = &(m_arrData[i + j - 1]); + pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev); + } + + i += nGroupCount - 1; // increment to skip all group controls + } + else // one control entry + { + RECT rectGroup = { 0, 0, 0, 0 }; + pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false); + } + } + + if(bVisible) + pT->SetRedraw(TRUE); + + pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + } + +// Message map and handlers + BEGIN_MSG_MAP(CDialogResize) + MESSAGE_HANDLER(WM_SIZE, OnSize) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) +#endif // _WIN32_WCE + END_MSG_MAP() + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); +#ifndef _WIN32_WCE + if(m_bGripper) + { + ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); + if(wParam == SIZE_MAXIMIZED) + wndGripper.ShowWindow(SW_HIDE); + else if(wParam == SIZE_RESTORED) + wndGripper.ShowWindow(SW_SHOW); + } +#endif // _WIN32_WCE + if(wParam != SIZE_MINIMIZED) + { + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + return 0; + } + +#ifndef _WIN32_WCE + LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + if(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1) + { + LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; + lpMMI->ptMinTrackSize = m_ptMinTrackSize; + } + return 0; + } +#endif // _WIN32_WCE + +// Implementation + bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup, + _AtlDlgResizeData* pDataPrev = NULL) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATL::CWindow ctl; + RECT rectCtl = { 0 }; + + ctl = pT->GetDlgItem(data.m_nCtlID); + if(!ctl.GetWindowRect(&rectCtl)) + return false; + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); + + if(bGroup) + { + if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) + { + int cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx; + int cxCtl = data.m_rect.right - data.m_rect.left; + rectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2; + rectCtl.right = rectCtl.left + cxCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) + { + rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); + + if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0) + { + rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); + + if(pDataPrev != NULL) + { + ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); + RECT rcPrev = { 0 }; + ctlPrev.GetWindowRect(&rcPrev); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); + int dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right); + rcPrev.right += dxAdjust; + ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); + } + } + else + { + rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left); + } + } + + if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) + { + int cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy; + int cyCtl = data.m_rect.bottom - data.m_rect.top; + rectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2; + rectCtl.bottom = rectCtl.top + cyCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) + { + rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); + + if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0) + { + rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); + + if(pDataPrev != NULL) + { + ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); + RECT rcPrev = { 0 }; + ctlPrev.GetWindowRect(&rcPrev); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); + int dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom); + rcPrev.bottom += dxAdjust; + ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); + } + } + else + { + rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top); + } + } + } + else // no group + { + if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) + { + int cxCtl = data.m_rect.right - data.m_rect.left; + rectCtl.left = (cxWidth - cxCtl) / 2; + rectCtl.right = rectCtl.left + cxCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) + { + rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx); + + if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0) + rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left); + } + + if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) + { + int cyCtl = data.m_rect.bottom - data.m_rect.top; + rectCtl.top = (cyHeight - cyCtl) / 2; + rectCtl.bottom = rectCtl.top + cyCtl; + } + else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) + { + rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy); + + if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0) + rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top); + } + } + + if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0) + ctl.Invalidate(); + + if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | DLSZ_CENTER_X | DLSZ_CENTER_Y)) != 0) + ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE); + + return true; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDoubleBufferImpl - Provides double-buffer painting support to any window + +template +class CDoubleBufferImpl +{ +public: +// Overrideables + void DoPaint(CDCHandle /*dc*/) + { + // must be implemented in a derived class + ATLASSERT(FALSE); + } + +// Message map and handlers + BEGIN_MSG_MAP(CDoubleBufferImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background painting needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + if(wParam != NULL) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + CMemoryDC dcMem((HDC)wParam, rect); + pT->DoPaint(dcMem.m_hDC); + } + else + { + CPaintDC dc(pT->m_hWnd); + CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint); + pT->DoPaint(dcMem.m_hDC); + } + + return 0; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CDoubleBufferWindowImpl - Implements a double-buffer painting window + +template +class ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T > +{ +public: + BEGIN_MSG_MAP(CDoubleBufferWindowImpl) + CHAIN_MSG_MAP(CDoubleBufferImpl< T >) + END_MSG_MAP() +}; + + +// command bar support +#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + #undef CBRM_GETMENU + #undef CBRM_TRACKPOPUPMENU + #undef CBRM_GETCMDBAR + #undef CBRPOPUPMENU +#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) + +}; // namespace WTL + +#endif // __ATLFRAME_H__ diff --git a/wtl/wtl/include/atlgdi.h b/wtl/wtl/include/atlgdi.h new file mode 100644 index 00000000..49a1371c --- /dev/null +++ b/wtl/wtl/include/atlgdi.h @@ -0,0 +1,3850 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLGDI_H__ +#define __ATLGDI_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlgdi.h requires atlapp.h to be included first +#endif + + +// protect template members from windowsx.h macros +#ifdef _INC_WINDOWSX + #undef CopyRgn + #undef CreateBrush + #undef CreatePen + #undef SelectBrush + #undef SelectPen + #undef SelectFont + #undef SelectBitmap +#endif // _INC_WINDOWSX + +// required libraries +#if !defined(_ATL_NO_MSIMG) && !defined(_WIN32_WCE) + #pragma comment(lib, "msimg32.lib") +#endif // !defined(_ATL_NO_MSIMG) && !defined(_WIN32_WCE) +#if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) + #pragma comment(lib, "opengl32.lib") +#endif // !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CPenT +// CBrushT +// CLogFont +// CFontT +// CBitmapT +// CPaletteT +// CRgnT +// CDCT +// CPaintDC +// CClientDC +// CWindowDC +// CMemoryDC +// CEnhMetaFileInfo +// CEnhMetaFileT +// CEnhMetaFileDC +// +// Global functions: +// AtlGetBitmapResourceInfo() +// AtlGetBitmapResourceBitsPerPixel() +// AtlIsAlphaBitmapResource() +// AtlIsDib16() +// AtlGetDibColorTableSize() +// AtlGetDibNumColors(), +// AtlGetDibBitmap() +// AtlCopyBitmap() +// AtlCreatePackedDib16() +// AtlSetClipboardDib16() +// AtlGetClipboardDib() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// Bitmap resource helpers to extract bitmap information for a bitmap resource + +inline LPBITMAPINFOHEADER AtlGetBitmapResourceInfo(HMODULE hModule, ATL::_U_STRINGorID image) +{ + HRSRC hResource = ::FindResource(hModule, image.m_lpstr, RT_BITMAP); + ATLASSERT(hResource != NULL); + HGLOBAL hGlobal = ::LoadResource(hModule, hResource); + ATLASSERT(hGlobal != NULL); + LPBITMAPINFOHEADER pBitmapInfoHeader = (LPBITMAPINFOHEADER)::LockResource(hGlobal); + ATLASSERT(pBitmapInfoHeader != NULL); + return pBitmapInfoHeader; +} + +inline WORD AtlGetBitmapResourceBitsPerPixel(HMODULE hModule, ATL::_U_STRINGorID image) +{ + LPBITMAPINFOHEADER pBitmapInfoHeader = AtlGetBitmapResourceInfo(hModule, image); + ATLASSERT(pBitmapInfoHeader != NULL); + return pBitmapInfoHeader->biBitCount; +} + +inline WORD AtlGetBitmapResourceBitsPerPixel(ATL::_U_STRINGorID image) +{ + return AtlGetBitmapResourceBitsPerPixel(ModuleHelper::GetResourceInstance(), image); +} + +/////////////////////////////////////////////////////////////////////////////// +// 32-bit (alpha channel) bitmap resource helper + +// Note: 32-bit (alpha channel) images work only on Windows XP with Common Controls version 6. +// If you want your app to work on older version of Windows, load non-alpha images if Common +// Controls version is less than 6. + +inline bool AtlIsAlphaBitmapResource(ATL::_U_STRINGorID image) +{ + return (AtlGetBitmapResourceBitsPerPixel(image) == 32); +} + + +/////////////////////////////////////////////////////////////////////////////// +// CPen + +template +class CPenT +{ +public: +// Data members + HPEN m_hPen; + +// Constructor/destructor/operators + CPenT(HPEN hPen = NULL) : m_hPen(hPen) + { } + + ~CPenT() + { + if(t_bManaged && m_hPen != NULL) + DeleteObject(); + } + + CPenT& operator =(HPEN hPen) + { + Attach(hPen); + return *this; + } + + void Attach(HPEN hPen) + { + if(t_bManaged && m_hPen != NULL && m_hPen != hPen) + ::DeleteObject(m_hPen); + m_hPen = hPen; + } + + HPEN Detach() + { + HPEN hPen = m_hPen; + m_hPen = NULL; + return hPen; + } + + operator HPEN() const { return m_hPen; } + + bool IsNull() const { return (m_hPen == NULL); } + +// Create methods + HPEN CreatePen(int nPenStyle, int nWidth, COLORREF crColor) + { + ATLASSERT(m_hPen == NULL); + m_hPen = ::CreatePen(nPenStyle, nWidth, crColor); + return m_hPen; + } + +#ifndef _WIN32_WCE + HPEN CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL) + { + ATLASSERT(m_hPen == NULL); + m_hPen = ::ExtCreatePen(nPenStyle, nWidth, pLogBrush, nStyleCount, lpStyle); + return m_hPen; + } +#endif // !_WIN32_WCE + + HPEN CreatePenIndirect(LPLOGPEN lpLogPen) + { + ATLASSERT(m_hPen == NULL); + m_hPen = ::CreatePenIndirect(lpLogPen); + return m_hPen; + } + + BOOL DeleteObject() + { + ATLASSERT(m_hPen != NULL); + BOOL bRet = ::DeleteObject(m_hPen); + if(bRet) + m_hPen = NULL; + return bRet; + } + +// Attributes + int GetLogPen(LOGPEN* pLogPen) const + { + ATLASSERT(m_hPen != NULL); + return ::GetObject(m_hPen, sizeof(LOGPEN), pLogPen); + } + + bool GetLogPen(LOGPEN& LogPen) const + { + ATLASSERT(m_hPen != NULL); + return (::GetObject(m_hPen, sizeof(LOGPEN), &LogPen) == sizeof(LOGPEN)); + } + +#ifndef _WIN32_WCE + int GetExtLogPen(EXTLOGPEN* pLogPen) const + { + ATLASSERT(m_hPen != NULL); + return ::GetObject(m_hPen, sizeof(EXTLOGPEN), pLogPen); + } + + bool GetExtLogPen(EXTLOGPEN& ExtLogPen) const + { + ATLASSERT(m_hPen != NULL); + return (::GetObject(m_hPen, sizeof(EXTLOGPEN), &ExtLogPen) == sizeof(EXTLOGPEN)); + } +#endif // !_WIN32_WCE +}; + +typedef CPenT CPenHandle; +typedef CPenT CPen; + + +/////////////////////////////////////////////////////////////////////////////// +// CBrush + +template +class CBrushT +{ +public: +// Data members + HBRUSH m_hBrush; + +// Constructor/destructor/operators + CBrushT(HBRUSH hBrush = NULL) : m_hBrush(hBrush) + { } + + ~CBrushT() + { + if(t_bManaged && m_hBrush != NULL) + DeleteObject(); + } + + CBrushT& operator =(HBRUSH hBrush) + { + Attach(hBrush); + return *this; + } + + void Attach(HBRUSH hBrush) + { + if(t_bManaged && m_hBrush != NULL && m_hBrush != hBrush) + ::DeleteObject(m_hBrush); + m_hBrush = hBrush; + } + + HBRUSH Detach() + { + HBRUSH hBrush = m_hBrush; + m_hBrush = NULL; + return hBrush; + } + + operator HBRUSH() const { return m_hBrush; } + + bool IsNull() const { return (m_hBrush == NULL); } + +// Create methods + HBRUSH CreateSolidBrush(COLORREF crColor) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::CreateSolidBrush(crColor); + return m_hBrush; + } + +#ifndef _WIN32_WCE + HBRUSH CreateHatchBrush(int nIndex, COLORREF crColor) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::CreateHatchBrush(nIndex, crColor); + return m_hBrush; + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + HBRUSH CreateBrushIndirect(const LOGBRUSH* lpLogBrush) + { + ATLASSERT(m_hBrush == NULL); +#ifndef _WIN32_WCE + m_hBrush = ::CreateBrushIndirect(lpLogBrush); +#else // CE specific + m_hBrush = ATL::CreateBrushIndirect(lpLogBrush); +#endif // _WIN32_WCE + return m_hBrush; + } +#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + + HBRUSH CreatePatternBrush(HBITMAP hBitmap) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::CreatePatternBrush(hBitmap); + return m_hBrush; + } + + HBRUSH CreateDIBPatternBrush(HGLOBAL hPackedDIB, UINT nUsage) + { + ATLASSERT(hPackedDIB != NULL); + const void* lpPackedDIB = GlobalLock(hPackedDIB); + ATLASSERT(lpPackedDIB != NULL); + m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage); + GlobalUnlock(hPackedDIB); + return m_hBrush; + } + + HBRUSH CreateDIBPatternBrush(const void* lpPackedDIB, UINT nUsage) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage); + return m_hBrush; + } + + HBRUSH CreateSysColorBrush(int nIndex) + { + ATLASSERT(m_hBrush == NULL); + m_hBrush = ::GetSysColorBrush(nIndex); + return m_hBrush; + } + + BOOL DeleteObject() + { + ATLASSERT(m_hBrush != NULL); + BOOL bRet = ::DeleteObject(m_hBrush); + if(bRet) + m_hBrush = NULL; + return bRet; + } + +// Attributes + int GetLogBrush(LOGBRUSH* pLogBrush) const + { + ATLASSERT(m_hBrush != NULL); + return ::GetObject(m_hBrush, sizeof(LOGBRUSH), pLogBrush); + } + + bool GetLogBrush(LOGBRUSH& LogBrush) const + { + ATLASSERT(m_hBrush != NULL); + return (::GetObject(m_hBrush, sizeof(LOGBRUSH), &LogBrush) == sizeof(LOGBRUSH)); + } +}; + +typedef CBrushT CBrushHandle; +typedef CBrushT CBrush; + + +/////////////////////////////////////////////////////////////////////////////// +// CFont + +class CLogFont : public LOGFONT +{ +public: + CLogFont() + { + memset(this, 0, sizeof(LOGFONT)); + } + + CLogFont(const LOGFONT& lf) + { + Copy(&lf); + } + + CLogFont(HFONT hFont) + { + ATLASSERT(::GetObjectType(hFont) == OBJ_FONT); + ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this); + } + + HFONT CreateFontIndirect() + { + return ::CreateFontIndirect(this); + } + + void SetBold() + { + lfWeight = FW_BOLD; + } + + bool IsBold() const + { + return (lfWeight >= FW_BOLD); + } + + void MakeBolder(int iScale = 1) + { + lfWeight += FW_BOLD * iScale; + } + + void MakeLarger(int iScale) + { + if(lfHeight > 0) + lfHeight += iScale; + else + lfHeight -= iScale; + } + + void SetHeight(LONG nPointSize, HDC hDC = NULL) + { + // For MM_TEXT mapping mode + lfHeight = -::MulDiv(nPointSize, ::GetDeviceCaps(hDC, LOGPIXELSY), 72); + } + + LONG GetHeight(HDC hDC = NULL) const + { + // For MM_TEXT mapping mode + return ::MulDiv(-lfHeight, 72, ::GetDeviceCaps(hDC, LOGPIXELSY)); + } + + LONG GetDeciPointHeight(HDC hDC = NULL) const + { +#ifndef _WIN32_WCE + POINT ptOrg = { 0, 0 }; + ::DPtoLP(hDC, &ptOrg, 1); + POINT pt = { 0, 0 }; + pt.y = abs(lfHeight) + ptOrg.y; + ::LPtoDP(hDC,&pt,1); + return ::MulDiv(pt.y, 720, ::GetDeviceCaps(hDC, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point +#else // CE specific + // DP and LP are always the same on CE + return ::MulDiv(abs(lfHeight), 720, ::GetDeviceCaps(hDC, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point +#endif // _WIN32_WCE + } + + void SetHeightFromDeciPoint(LONG nDeciPtHeight, HDC hDC = NULL) + { +#ifndef _WIN32_WCE + POINT pt = { 0, 0 }; + pt.y = ::MulDiv(::GetDeviceCaps(hDC, LOGPIXELSY), nDeciPtHeight, 720); // 72 points/inch, 10 decipoints/point + ::DPtoLP(hDC, &pt, 1); + POINT ptOrg = { 0, 0 }; + ::DPtoLP(hDC, &ptOrg, 1); + lfHeight = -abs(pt.y - ptOrg.y); +#else // CE specific + // DP and LP are always the same on CE + lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC, LOGPIXELSY), nDeciPtHeight, 720)); // 72 points/inch, 10 decipoints/point +#endif // _WIN32_WCE + } + +#ifndef _WIN32_WCE + void SetCaptionFont() + { + NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); + Copy(&ncm.lfCaptionFont); + } + + void SetMenuFont() + { + NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); + Copy(&ncm.lfMenuFont); + } + + void SetStatusFont() + { + NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); + Copy(&ncm.lfStatusFont); + } + + void SetMessageBoxFont() + { + NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; + ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); + Copy(&ncm.lfMessageFont); + } +#endif // !_WIN32_WCE + + void Copy(const LOGFONT* pLogFont) + { + ATLASSERT(pLogFont != NULL); + *(LOGFONT*)this = *pLogFont; + } + + CLogFont& operator =(const CLogFont& src) + { + Copy(&src); + return *this; + } + + CLogFont& operator =(const LOGFONT& src) + { + Copy(&src); + return *this; + } + + CLogFont& operator =(HFONT hFont) + { + ATLASSERT(::GetObjectType(hFont) == OBJ_FONT); + ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this); + return *this; + } + + bool operator ==(const LOGFONT& logfont) const + { + return(logfont.lfHeight == lfHeight && + logfont.lfWidth == lfWidth && + logfont.lfEscapement == lfEscapement && + logfont.lfOrientation == lfOrientation && + logfont.lfWeight == lfWeight && + logfont.lfItalic == lfItalic && + logfont.lfUnderline == lfUnderline && + logfont.lfStrikeOut == lfStrikeOut && + logfont.lfCharSet == lfCharSet && + logfont.lfOutPrecision == lfOutPrecision && + logfont.lfClipPrecision == lfClipPrecision && + logfont.lfQuality == lfQuality && + logfont.lfPitchAndFamily == lfPitchAndFamily && + lstrcmp(logfont.lfFaceName, lfFaceName) == 0); + } +}; + + +template +class CFontT +{ +public: +// Data members + HFONT m_hFont; + +// Constructor/destructor/operators + CFontT(HFONT hFont = NULL) : m_hFont(hFont) + { } + + ~CFontT() + { + if(t_bManaged && m_hFont != NULL) + DeleteObject(); + } + + CFontT& operator =(HFONT hFont) + { + Attach(hFont); + return *this; + } + + void Attach(HFONT hFont) + { + if(t_bManaged && m_hFont != NULL && m_hFont != hFont) + ::DeleteObject(m_hFont); + m_hFont = hFont; + } + + HFONT Detach() + { + HFONT hFont = m_hFont; + m_hFont = NULL; + return hFont; + } + + operator HFONT() const { return m_hFont; } + + bool IsNull() const { return (m_hFont == NULL); } + +// Create methods + HFONT CreateFontIndirect(const LOGFONT* lpLogFont) + { + ATLASSERT(m_hFont == NULL); + m_hFont = ::CreateFontIndirect(lpLogFont); + return m_hFont; + } + +#if !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500) + HFONT CreateFontIndirectEx(CONST ENUMLOGFONTEXDV* penumlfex) + { + ATLASSERT(m_hFont == NULL); + m_hFont = ::CreateFontIndirectEx(penumlfex); + return m_hFont; + } +#endif // !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500) + +#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + HFONT CreateFont(int nHeight, int nWidth, int nEscapement, + int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline, + BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, + BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily, + LPCTSTR lpszFacename) + { + ATLASSERT(m_hFont == NULL); +#ifndef _WIN32_WCE + m_hFont = ::CreateFont(nHeight, nWidth, nEscapement, + nOrientation, nWeight, bItalic, bUnderline, cStrikeOut, + nCharSet, nOutPrecision, nClipPrecision, nQuality, + nPitchAndFamily, lpszFacename); +#else // CE specific + m_hFont = ATL::CreateFont(nHeight, nWidth, nEscapement, + nOrientation, nWeight, bItalic, bUnderline, cStrikeOut, + nCharSet, nOutPrecision, nClipPrecision, nQuality, + nPitchAndFamily, lpszFacename); +#endif // _WIN32_WCE + return m_hFont; + } +#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) + + HFONT CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, HDC hDC = NULL, bool bBold = false, bool bItalic = false) + { + LOGFONT logFont = { 0 }; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfHeight = nPointSize; + SecureHelper::strncpy_x(logFont.lfFaceName, _countof(logFont.lfFaceName), lpszFaceName, _TRUNCATE); + + if(bBold) + logFont.lfWeight = FW_BOLD; + if(bItalic) + logFont.lfItalic = (BYTE)TRUE; + + return CreatePointFontIndirect(&logFont, hDC); + } + + HFONT CreatePointFontIndirect(const LOGFONT* lpLogFont, HDC hDC = NULL) + { + HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); + + // convert nPointSize to logical units based on hDC + LOGFONT logFont = *lpLogFont; +#ifndef _WIN32_WCE + POINT pt = { 0, 0 }; + pt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720); // 72 points/inch, 10 decipoints/point + ::DPtoLP(hDC1, &pt, 1); + POINT ptOrg = { 0, 0 }; + ::DPtoLP(hDC1, &ptOrg, 1); + logFont.lfHeight = -abs(pt.y - ptOrg.y); +#else // CE specific + // DP and LP are always the same on CE + logFont.lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720)); // 72 points/inch, 10 decipoints/point +#endif // _WIN32_WCE + + if(hDC == NULL) + ::ReleaseDC(NULL, hDC1); + + return CreateFontIndirect(&logFont); + } + + BOOL DeleteObject() + { + ATLASSERT(m_hFont != NULL); + BOOL bRet = ::DeleteObject(m_hFont); + if(bRet) + m_hFont = NULL; + return bRet; + } + +// Attributes + int GetLogFont(LOGFONT* pLogFont) const + { + ATLASSERT(m_hFont != NULL); + return ::GetObject(m_hFont, sizeof(LOGFONT), pLogFont); + } + + bool GetLogFont(LOGFONT& LogFont) const + { + ATLASSERT(m_hFont != NULL); + return (::GetObject(m_hFont, sizeof(LOGFONT), &LogFont) == sizeof(LOGFONT)); + } +}; + +typedef CFontT CFontHandle; +typedef CFontT CFont; + + +/////////////////////////////////////////////////////////////////////////////// +// CBitmap + +template +class CBitmapT +{ +public: +// Data members + HBITMAP m_hBitmap; + +// Constructor/destructor/operators + CBitmapT(HBITMAP hBitmap = NULL) : m_hBitmap(hBitmap) + { } + + ~CBitmapT() + { + if(t_bManaged && m_hBitmap != NULL) + DeleteObject(); + } + + CBitmapT& operator =(HBITMAP hBitmap) + { + Attach(hBitmap); + return *this; + } + + void Attach(HBITMAP hBitmap) + { + if(t_bManaged && m_hBitmap != NULL&& m_hBitmap != hBitmap) + ::DeleteObject(m_hBitmap); + m_hBitmap = hBitmap; + } + + HBITMAP Detach() + { + HBITMAP hBitmap = m_hBitmap; + m_hBitmap = NULL; + return hBitmap; + } + + operator HBITMAP() const { return m_hBitmap; } + + bool IsNull() const { return (m_hBitmap == NULL); } + +// Create and load methods + HBITMAP LoadBitmap(ATL::_U_STRINGorID bitmap) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr); + return m_hBitmap; + } + + HBITMAP LoadOEMBitmap(UINT nIDBitmap) // for OBM_/OCR_/OIC_ + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::LoadBitmap(NULL, MAKEINTRESOURCE(nIDBitmap)); + return m_hBitmap; + } + +#ifndef _WIN32_WCE + HBITMAP LoadMappedBitmap(UINT nIDBitmap, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateMappedBitmap(ModuleHelper::GetResourceInstance(), nIDBitmap, (WORD)nFlags, lpColorMap, nMapSize); + return m_hBitmap; + } +#endif // !_WIN32_WCE + + HBITMAP CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitsPerPixel, const void* lpBits) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateBitmap(nWidth, nHeight, nPlanes, nBitsPerPixel, lpBits); + return m_hBitmap; + } + +#ifndef _WIN32_WCE + HBITMAP CreateBitmapIndirect(LPBITMAP lpBitmap) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateBitmapIndirect(lpBitmap); + return m_hBitmap; + } +#endif // !_WIN32_WCE + + HBITMAP CreateCompatibleBitmap(HDC hDC, int nWidth, int nHeight) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateCompatibleBitmap(hDC, nWidth, nHeight); + return m_hBitmap; + } + +#ifndef _WIN32_WCE + HBITMAP CreateDiscardableBitmap(HDC hDC, int nWidth, int nHeight) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateDiscardableBitmap(hDC, nWidth, nHeight); + return m_hBitmap; + } +#endif // !_WIN32_WCE + + BOOL DeleteObject() + { + ATLASSERT(m_hBitmap != NULL); + BOOL bRet = ::DeleteObject(m_hBitmap); + if(bRet) + m_hBitmap = NULL; + return bRet; + } + +// Attributes + int GetBitmap(BITMAP* pBitMap) const + { + ATLASSERT(m_hBitmap != NULL); + return ::GetObject(m_hBitmap, sizeof(BITMAP), pBitMap); + } + + bool GetBitmap(BITMAP& bm) const + { + ATLASSERT(m_hBitmap != NULL); + return (::GetObject(m_hBitmap, sizeof(BITMAP), &bm) == sizeof(BITMAP)); + } + + bool GetSize(SIZE& size) const + { + ATLASSERT(m_hBitmap != NULL); + BITMAP bm = { 0 }; + if(!GetBitmap(&bm)) + return false; + size.cx = bm.bmWidth; + size.cy = bm.bmHeight; + return true; + } + +#ifndef _WIN32_WCE + DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits) const + { + ATLASSERT(m_hBitmap != NULL); + return ::GetBitmapBits(m_hBitmap, dwCount, lpBits); + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) + DWORD SetBitmapBits(DWORD dwCount, const void* lpBits) + { + ATLASSERT(m_hBitmap != NULL); + return ::SetBitmapBits(m_hBitmap, dwCount, lpBits); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) + +#ifndef _WIN32_WCE + BOOL GetBitmapDimension(LPSIZE lpSize) const + { + ATLASSERT(m_hBitmap != NULL); + return ::GetBitmapDimensionEx(m_hBitmap, lpSize); + } + + BOOL SetBitmapDimension(int nWidth, int nHeight, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hBitmap != NULL); + return ::SetBitmapDimensionEx(m_hBitmap, nWidth, nHeight, lpSize); + } + +// DIB support + HBITMAP CreateDIBitmap(HDC hDC, CONST BITMAPINFOHEADER* lpbmih, DWORD dwInit, CONST VOID* lpbInit, CONST BITMAPINFO* lpbmi, UINT uColorUse) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateDIBitmap(hDC, lpbmih, dwInit, lpbInit, lpbmi, uColorUse); + return m_hBitmap; + } +#endif // !_WIN32_WCE + + HBITMAP CreateDIBSection(HDC hDC, CONST BITMAPINFO* lpbmi, UINT uColorUse, VOID** ppvBits, HANDLE hSection, DWORD dwOffset) + { + ATLASSERT(m_hBitmap == NULL); + m_hBitmap = ::CreateDIBSection(hDC, lpbmi, uColorUse, ppvBits, hSection, dwOffset); + return m_hBitmap; + } + +#ifndef _WIN32_WCE + int GetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines, LPVOID lpvBits, LPBITMAPINFO lpbmi, UINT uColorUse) const + { + ATLASSERT(m_hBitmap != NULL); + return ::GetDIBits(hDC, m_hBitmap, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse); + } + + int SetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse) + { + ATLASSERT(m_hBitmap != NULL); + return ::SetDIBits(hDC, m_hBitmap, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse); + } +#endif // !_WIN32_WCE +}; + +typedef CBitmapT CBitmapHandle; +typedef CBitmapT CBitmap; + + +/////////////////////////////////////////////////////////////////////////////// +// CPalette + +template +class CPaletteT +{ +public: +// Data members + HPALETTE m_hPalette; + +// Constructor/destructor/operators + CPaletteT(HPALETTE hPalette = NULL) : m_hPalette(hPalette) + { } + + ~CPaletteT() + { + if(t_bManaged && m_hPalette != NULL) + DeleteObject(); + } + + CPaletteT& operator =(HPALETTE hPalette) + { + Attach(hPalette); + return *this; + } + + void Attach(HPALETTE hPalette) + { + if(t_bManaged && m_hPalette != NULL && m_hPalette != hPalette) + ::DeleteObject(m_hPalette); + m_hPalette = hPalette; + } + + HPALETTE Detach() + { + HPALETTE hPalette = m_hPalette; + m_hPalette = NULL; + return hPalette; + } + + operator HPALETTE() const { return m_hPalette; } + + bool IsNull() const { return (m_hPalette == NULL); } + +// Create methods + HPALETTE CreatePalette(LPLOGPALETTE lpLogPalette) + { + ATLASSERT(m_hPalette == NULL); + m_hPalette = ::CreatePalette(lpLogPalette); + return m_hPalette; + } + +#ifndef _WIN32_WCE + HPALETTE CreateHalftonePalette(HDC hDC) + { + ATLASSERT(m_hPalette == NULL); + ATLASSERT(hDC != NULL); + m_hPalette = ::CreateHalftonePalette(hDC); + return m_hPalette; + } +#endif // !_WIN32_WCE + + BOOL DeleteObject() + { + ATLASSERT(m_hPalette != NULL); + BOOL bRet = ::DeleteObject(m_hPalette); + if(bRet) + m_hPalette = NULL; + return bRet; + } + +// Attributes + int GetEntryCount() const + { + ATLASSERT(m_hPalette != NULL); + WORD nEntries = 0; + ::GetObject(m_hPalette, sizeof(WORD), &nEntries); + return (int)nEntries; + } + + UINT GetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) const + { + ATLASSERT(m_hPalette != NULL); + return ::GetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors); + } + + UINT SetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) + { + ATLASSERT(m_hPalette != NULL); + return ::SetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors); + } + +// Operations +#ifndef _WIN32_WCE + void AnimatePalette(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) + { + ATLASSERT(m_hPalette != NULL); + ::AnimatePalette(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors); + } + + BOOL ResizePalette(UINT nNumEntries) + { + ATLASSERT(m_hPalette != NULL); + return ::ResizePalette(m_hPalette, nNumEntries); + } +#endif // !_WIN32_WCE + + UINT GetNearestPaletteIndex(COLORREF crColor) const + { + ATLASSERT(m_hPalette != NULL); + return ::GetNearestPaletteIndex(m_hPalette, crColor); + } +}; + +typedef CPaletteT CPaletteHandle; +typedef CPaletteT CPalette; + + +/////////////////////////////////////////////////////////////////////////////// +// CRgn + +template +class CRgnT +{ +public: +// Data members + HRGN m_hRgn; + +// Constructor/destructor/operators + CRgnT(HRGN hRgn = NULL) : m_hRgn(hRgn) + { } + + ~CRgnT() + { + if(t_bManaged && m_hRgn != NULL) + DeleteObject(); + } + + CRgnT& operator =(HRGN hRgn) + { + Attach(hRgn); + return *this; + } + + void Attach(HRGN hRgn) + { + if(t_bManaged && m_hRgn != NULL && m_hRgn != hRgn) + ::DeleteObject(m_hRgn); + m_hRgn = hRgn; + } + + HRGN Detach() + { + HRGN hRgn = m_hRgn; + m_hRgn = NULL; + return hRgn; + } + + operator HRGN() const { return m_hRgn; } + + bool IsNull() const { return (m_hRgn == NULL); } + +// Create methods + HRGN CreateRectRgn(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateRectRgn(x1, y1, x2, y2); + return m_hRgn; + } + + HRGN CreateRectRgnIndirect(LPCRECT lpRect) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateRectRgnIndirect(lpRect); + return m_hRgn; + } + +#ifndef _WIN32_WCE + HRGN CreateEllipticRgn(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateEllipticRgn(x1, y1, x2, y2); + return m_hRgn; + } + + HRGN CreateEllipticRgnIndirect(LPCRECT lpRect) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateEllipticRgnIndirect(lpRect); + return m_hRgn; + } + + HRGN CreatePolygonRgn(LPPOINT lpPoints, int nCount, int nMode) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreatePolygonRgn(lpPoints, nCount, nMode); + return m_hRgn; + } + + HRGN CreatePolyPolygonRgn(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount, int nPolyFillMode) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreatePolyPolygonRgn(lpPoints, lpPolyCounts, nCount, nPolyFillMode); + return m_hRgn; + } + + HRGN CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::CreateRoundRectRgn(x1, y1, x2, y2, x3, y3); + return m_hRgn; + } + + HRGN CreateFromPath(HDC hDC) + { + ATLASSERT(m_hRgn == NULL); + ATLASSERT(hDC != NULL); + m_hRgn = ::PathToRegion(hDC); + return m_hRgn; + } + + HRGN CreateFromData(const XFORM* lpXForm, int nCount, const RGNDATA* pRgnData) + { + ATLASSERT(m_hRgn == NULL); + m_hRgn = ::ExtCreateRegion(lpXForm, nCount, pRgnData); + return m_hRgn; + } +#endif // !_WIN32_WCE + + BOOL DeleteObject() + { + ATLASSERT(m_hRgn != NULL); + BOOL bRet = ::DeleteObject(m_hRgn); + if(bRet) + m_hRgn = NULL; + return bRet; + } + +// Operations + void SetRectRgn(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hRgn != NULL); + ::SetRectRgn(m_hRgn, x1, y1, x2, y2); + } + + void SetRectRgn(LPCRECT lpRect) + { + ATLASSERT(m_hRgn != NULL); + ::SetRectRgn(m_hRgn, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + + int CombineRgn(HRGN hRgnSrc1, HRGN hRgnSrc2, int nCombineMode) + { + ATLASSERT(m_hRgn != NULL); + return ::CombineRgn(m_hRgn, hRgnSrc1, hRgnSrc2, nCombineMode); + } + + int CombineRgn(HRGN hRgnSrc, int nCombineMode) + { + ATLASSERT(m_hRgn != NULL); + return ::CombineRgn(m_hRgn, m_hRgn, hRgnSrc, nCombineMode); + } + + int CopyRgn(HRGN hRgnSrc) + { + ATLASSERT(m_hRgn != NULL); + return ::CombineRgn(m_hRgn, hRgnSrc, NULL, RGN_COPY); + } + + BOOL EqualRgn(HRGN hRgn) const + { + ATLASSERT(m_hRgn != NULL); + return ::EqualRgn(m_hRgn, hRgn); + } + + int OffsetRgn(int x, int y) + { + ATLASSERT(m_hRgn != NULL); + return ::OffsetRgn(m_hRgn, x, y); + } + + int OffsetRgn(POINT point) + { + ATLASSERT(m_hRgn != NULL); + return ::OffsetRgn(m_hRgn, point.x, point.y); + } + + int GetRgnBox(LPRECT lpRect) const + { + ATLASSERT(m_hRgn != NULL); + return ::GetRgnBox(m_hRgn, lpRect); + } + + BOOL PtInRegion(int x, int y) const + { + ATLASSERT(m_hRgn != NULL); + return ::PtInRegion(m_hRgn, x, y); + } + + BOOL PtInRegion(POINT point) const + { + ATLASSERT(m_hRgn != NULL); + return ::PtInRegion(m_hRgn, point.x, point.y); + } + + BOOL RectInRegion(LPCRECT lpRect) const + { + ATLASSERT(m_hRgn != NULL); + return ::RectInRegion(m_hRgn, lpRect); + } + + int GetRegionData(LPRGNDATA lpRgnData, int nDataSize) const + { + ATLASSERT(m_hRgn != NULL); + return (int)::GetRegionData(m_hRgn, nDataSize, lpRgnData); + } +}; + +typedef CRgnT CRgnHandle; +typedef CRgnT CRgn; + + +/////////////////////////////////////////////////////////////////////////////// +// CDC - The device context class + +template +class CDCT +{ +public: +// Data members + HDC m_hDC; + +// Constructor/destructor/operators + CDCT(HDC hDC = NULL) : m_hDC(hDC) + { + } + + ~CDCT() + { + if(t_bManaged && m_hDC != NULL) + ::DeleteDC(Detach()); + } + + CDCT& operator =(HDC hDC) + { + Attach(hDC); + return *this; + } + + void Attach(HDC hDC) + { + if(t_bManaged && m_hDC != NULL && m_hDC != hDC) + ::DeleteDC(m_hDC); + m_hDC = hDC; + } + + HDC Detach() + { + HDC hDC = m_hDC; + m_hDC = NULL; + return hDC; + } + + operator HDC() const { return m_hDC; } + + bool IsNull() const { return (m_hDC == NULL); } + +// Operations +#ifndef _WIN32_WCE + HWND WindowFromDC() const + { + ATLASSERT(m_hDC != NULL); + return ::WindowFromDC(m_hDC); + } +#endif // !_WIN32_WCE + + CPenHandle GetCurrentPen() const + { + ATLASSERT(m_hDC != NULL); + return CPenHandle((HPEN)::GetCurrentObject(m_hDC, OBJ_PEN)); + } + + CBrushHandle GetCurrentBrush() const + { + ATLASSERT(m_hDC != NULL); + return CBrushHandle((HBRUSH)::GetCurrentObject(m_hDC, OBJ_BRUSH)); + } + + CPaletteHandle GetCurrentPalette() const + { + ATLASSERT(m_hDC != NULL); + return CPaletteHandle((HPALETTE)::GetCurrentObject(m_hDC, OBJ_PAL)); + } + + CFontHandle GetCurrentFont() const + { + ATLASSERT(m_hDC != NULL); + return CFontHandle((HFONT)::GetCurrentObject(m_hDC, OBJ_FONT)); + } + + CBitmapHandle GetCurrentBitmap() const + { + ATLASSERT(m_hDC != NULL); + return CBitmapHandle((HBITMAP)::GetCurrentObject(m_hDC, OBJ_BITMAP)); + } + + HDC CreateDC(LPCTSTR lpszDriverName, LPCTSTR lpszDeviceName, LPCTSTR lpszOutput, const DEVMODE* lpInitData) + { + ATLASSERT(m_hDC == NULL); + m_hDC = ::CreateDC(lpszDriverName, lpszDeviceName, lpszOutput, lpInitData); + return m_hDC; + } + + HDC CreateCompatibleDC(HDC hDC = NULL) + { + ATLASSERT(m_hDC == NULL); + m_hDC = ::CreateCompatibleDC(hDC); + return m_hDC; + } + + BOOL DeleteDC() + { + if(m_hDC == NULL) + return FALSE; + BOOL bRet = ::DeleteDC(m_hDC); + if(bRet) + m_hDC = NULL; + return bRet; + } + +// Device-Context Functions + int SaveDC() + { + ATLASSERT(m_hDC != NULL); + return ::SaveDC(m_hDC); + } + + BOOL RestoreDC(int nSavedDC) + { + ATLASSERT(m_hDC != NULL); + return ::RestoreDC(m_hDC, nSavedDC); + } + + int GetDeviceCaps(int nIndex) const + { + ATLASSERT(m_hDC != NULL); + return ::GetDeviceCaps(m_hDC, nIndex); + } + +#ifndef _WIN32_WCE + UINT SetBoundsRect(LPCRECT lpRectBounds, UINT flags) + { + ATLASSERT(m_hDC != NULL); + return ::SetBoundsRect(m_hDC, lpRectBounds, flags); + } + + UINT GetBoundsRect(LPRECT lpRectBounds, UINT flags) const + { + ATLASSERT(m_hDC != NULL); + return ::GetBoundsRect(m_hDC, lpRectBounds, flags); + } + + BOOL ResetDC(const DEVMODE* lpDevMode) + { + ATLASSERT(m_hDC != NULL); + return ::ResetDC(m_hDC, lpDevMode) != NULL; + } + +// Drawing-Tool Functions + BOOL GetBrushOrg(LPPOINT lpPoint) const + { + ATLASSERT(m_hDC != NULL); + return ::GetBrushOrgEx(m_hDC, lpPoint); + } +#endif // !_WIN32_WCE + + BOOL SetBrushOrg(int x, int y, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetBrushOrgEx(m_hDC, x, y, lpPoint); + } + + BOOL SetBrushOrg(POINT point, LPPOINT lpPointRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetBrushOrgEx(m_hDC, point.x, point.y, lpPointRet); + } + +#ifndef _WIN32_WCE + int EnumObjects(int nObjectType, int (CALLBACK* lpfn)(LPVOID, LPARAM), LPARAM lpData) + { + ATLASSERT(m_hDC != NULL); +#ifdef STRICT + return ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, lpData); +#else + return ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, (LPVOID)lpData); +#endif + } +#endif // !_WIN32_WCE + +// Type-safe selection helpers + HPEN SelectPen(HPEN hPen) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + ATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN || ::GetObjectType(hPen) == OBJ_EXTPEN); +#else // CE specific + ATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN); +#endif // _WIN32_WCE + return (HPEN)::SelectObject(m_hDC, hPen); + } + + HBRUSH SelectBrush(HBRUSH hBrush) + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(hBrush == NULL || ::GetObjectType(hBrush) == OBJ_BRUSH); + return (HBRUSH)::SelectObject(m_hDC, hBrush); + } + + HFONT SelectFont(HFONT hFont) + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(hFont == NULL || ::GetObjectType(hFont) == OBJ_FONT); + return (HFONT)::SelectObject(m_hDC, hFont); + } + + HBITMAP SelectBitmap(HBITMAP hBitmap) + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(hBitmap == NULL || ::GetObjectType(hBitmap) == OBJ_BITMAP); + return (HBITMAP)::SelectObject(m_hDC, hBitmap); + } + + int SelectRgn(HRGN hRgn) // special return for regions + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(hRgn == NULL || ::GetObjectType(hRgn) == OBJ_REGION); + return PtrToInt(::SelectObject(m_hDC, hRgn)); + } + +// Type-safe selection helpers for stock objects + HPEN SelectStockPen(int nPen) + { + ATLASSERT(m_hDC != NULL); +#if (_WIN32_WINNT >= 0x0500) + ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN); +#else + ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN); +#endif // !(_WIN32_WINNT >= 0x0500) + return SelectPen((HPEN)::GetStockObject(nPen)); + } + + HBRUSH SelectStockBrush(int nBrush) + { +#if (_WIN32_WINNT >= 0x0500) + ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH); +#else + ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH); +#endif // !(_WIN32_WINNT >= 0x0500) + return SelectBrush((HBRUSH)::GetStockObject(nBrush)); + } + + HFONT SelectStockFont(int nFont) + { +#ifndef _WIN32_WCE + ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT); +#else // CE specific + ATLASSERT(nFont == SYSTEM_FONT); +#endif // _WIN32_WCE + return SelectFont((HFONT)::GetStockObject(nFont)); + } + + HPALETTE SelectStockPalette(int nPalette, BOOL bForceBackground) + { + ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported + return SelectPalette((HPALETTE)::GetStockObject(nPalette), bForceBackground); + } + +// Color and Color Palette Functions + COLORREF GetNearestColor(COLORREF crColor) const + { + ATLASSERT(m_hDC != NULL); + return ::GetNearestColor(m_hDC, crColor); + } + + HPALETTE SelectPalette(HPALETTE hPalette, BOOL bForceBackground) + { + ATLASSERT(m_hDC != NULL); + + return ::SelectPalette(m_hDC, hPalette, bForceBackground); + } + + UINT RealizePalette() + { + ATLASSERT(m_hDC != NULL); + return ::RealizePalette(m_hDC); + } + +#ifndef _WIN32_WCE + void UpdateColors() + { + ATLASSERT(m_hDC != NULL); + ::UpdateColors(m_hDC); + } +#endif // !_WIN32_WCE + +// Drawing-Attribute Functions + COLORREF GetBkColor() const + { + ATLASSERT(m_hDC != NULL); + return ::GetBkColor(m_hDC); + } + + int GetBkMode() const + { + ATLASSERT(m_hDC != NULL); + return ::GetBkMode(m_hDC); + } + +#ifndef _WIN32_WCE + int GetPolyFillMode() const + { + ATLASSERT(m_hDC != NULL); + return ::GetPolyFillMode(m_hDC); + } + + int GetROP2() const + { + ATLASSERT(m_hDC != NULL); + return ::GetROP2(m_hDC); + } + + int GetStretchBltMode() const + { + ATLASSERT(m_hDC != NULL); + return ::GetStretchBltMode(m_hDC); + } +#endif // !_WIN32_WCE + + COLORREF GetTextColor() const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextColor(m_hDC); + } + + COLORREF SetBkColor(COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetBkColor(m_hDC, crColor); + } + + int SetBkMode(int nBkMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetBkMode(m_hDC, nBkMode); + } + +#ifndef _WIN32_WCE + int SetPolyFillMode(int nPolyFillMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetPolyFillMode(m_hDC, nPolyFillMode); + } +#endif // !_WIN32_WCE + + int SetROP2(int nDrawMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetROP2(m_hDC, nDrawMode); + } + +#ifndef _WIN32_WCE + int SetStretchBltMode(int nStretchMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetStretchBltMode(m_hDC, nStretchMode); + } +#endif // !_WIN32_WCE + + COLORREF SetTextColor(COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetTextColor(m_hDC, crColor); + } + +#ifndef _WIN32_WCE + BOOL GetColorAdjustment(LPCOLORADJUSTMENT lpColorAdjust) const + { + ATLASSERT(m_hDC != NULL); + return ::GetColorAdjustment(m_hDC, lpColorAdjust); + } + + BOOL SetColorAdjustment(const COLORADJUSTMENT* lpColorAdjust) + { + ATLASSERT(m_hDC != NULL); + return ::SetColorAdjustment(m_hDC, lpColorAdjust); + } + +// Mapping Functions + int GetMapMode() const + { + ATLASSERT(m_hDC != NULL); + return ::GetMapMode(m_hDC); + } + + BOOL GetViewportOrg(LPPOINT lpPoint) const + { + ATLASSERT(m_hDC != NULL); + return ::GetViewportOrgEx(m_hDC, lpPoint); + } + + int SetMapMode(int nMapMode) + { + ATLASSERT(m_hDC != NULL); + return ::SetMapMode(m_hDC, nMapMode); + } +#endif // !_WIN32_WCE + + // Viewport Origin + BOOL SetViewportOrg(int x, int y, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetViewportOrgEx(m_hDC, x, y, lpPoint); + } + + BOOL SetViewportOrg(POINT point, LPPOINT lpPointRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return SetViewportOrg(point.x, point.y, lpPointRet); + } + +#ifndef _WIN32_WCE + BOOL OffsetViewportOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::OffsetViewportOrgEx(m_hDC, nWidth, nHeight, lpPoint); + } + + // Viewport Extent + BOOL GetViewportExt(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetViewportExtEx(m_hDC, lpSize); + } + + BOOL SetViewportExt(int x, int y, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetViewportExtEx(m_hDC, x, y, lpSize); + } + + BOOL SetViewportExt(SIZE size, LPSIZE lpSizeRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return SetViewportExt(size.cx, size.cy, lpSizeRet); + } + + BOOL ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::ScaleViewportExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize); + } +#endif // !_WIN32_WCE + + // Window Origin +#ifndef _WIN32_WCE + BOOL GetWindowOrg(LPPOINT lpPoint) const + { + ATLASSERT(m_hDC != NULL); + return ::GetWindowOrgEx(m_hDC, lpPoint); + } + + BOOL SetWindowOrg(int x, int y, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetWindowOrgEx(m_hDC, x, y, lpPoint); + } + + BOOL SetWindowOrg(POINT point, LPPOINT lpPointRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return SetWindowOrg(point.x, point.y, lpPointRet); + } + + BOOL OffsetWindowOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::OffsetWindowOrgEx(m_hDC, nWidth, nHeight, lpPoint); + } + + // Window extent + BOOL GetWindowExt(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetWindowExtEx(m_hDC, lpSize); + } + + BOOL SetWindowExt(int x, int y, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::SetWindowExtEx(m_hDC, x, y, lpSize); + } + + BOOL SetWindowExt(SIZE size, LPSIZE lpSizeRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return SetWindowExt(size.cx, size.cy, lpSizeRet); + } + + BOOL ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::ScaleWindowExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize); + } + +// Coordinate Functions + BOOL DPtoLP(LPPOINT lpPoints, int nCount = 1) const + { + ATLASSERT(m_hDC != NULL); + return ::DPtoLP(m_hDC, lpPoints, nCount); + } + + BOOL DPtoLP(LPRECT lpRect) const + { + ATLASSERT(m_hDC != NULL); + return ::DPtoLP(m_hDC, (LPPOINT)lpRect, 2); + } + + BOOL DPtoLP(LPSIZE lpSize) const + { + SIZE sizeWinExt = { 0, 0 }; + if(!GetWindowExt(&sizeWinExt)) + return FALSE; + SIZE sizeVpExt = { 0, 0 }; + if(!GetViewportExt(&sizeVpExt)) + return FALSE; + lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeWinExt.cx), abs(sizeVpExt.cx)); + lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeWinExt.cy), abs(sizeVpExt.cy)); + return TRUE; + } + + BOOL LPtoDP(LPPOINT lpPoints, int nCount = 1) const + { + ATLASSERT(m_hDC != NULL); + return ::LPtoDP(m_hDC, lpPoints, nCount); + } + + BOOL LPtoDP(LPRECT lpRect) const + { + ATLASSERT(m_hDC != NULL); + return ::LPtoDP(m_hDC, (LPPOINT)lpRect, 2); + } + + BOOL LPtoDP(LPSIZE lpSize) const + { + SIZE sizeWinExt = { 0, 0 }; + if(!GetWindowExt(&sizeWinExt)) + return FALSE; + SIZE sizeVpExt = { 0, 0 }; + if(!GetViewportExt(&sizeVpExt)) + return FALSE; + lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeVpExt.cx), abs(sizeWinExt.cx)); + lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeVpExt.cy), abs(sizeWinExt.cy)); + return TRUE; + } + +// Special Coordinate Functions (useful for dealing with metafiles and OLE) + #define HIMETRIC_INCH 2540 // HIMETRIC units per inch + + void DPtoHIMETRIC(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + int nMapMode; + if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT) + { + // when using a constrained map mode, map against physical inch + ((CDCHandle*)this)->SetMapMode(MM_HIMETRIC); + DPtoLP(lpSize); + ((CDCHandle*)this)->SetMapMode(nMapMode); + } + else + { + // map against logical inch for non-constrained mapping modes + int cxPerInch = GetDeviceCaps(LOGPIXELSX); + int cyPerInch = GetDeviceCaps(LOGPIXELSY); + ATLASSERT(cxPerInch != 0 && cyPerInch != 0); + lpSize->cx = ::MulDiv(lpSize->cx, HIMETRIC_INCH, cxPerInch); + lpSize->cy = ::MulDiv(lpSize->cy, HIMETRIC_INCH, cyPerInch); + } + } + + void HIMETRICtoDP(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + int nMapMode; + if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT) + { + // when using a constrained map mode, map against physical inch + ((CDCHandle*)this)->SetMapMode(MM_HIMETRIC); + LPtoDP(lpSize); + ((CDCHandle*)this)->SetMapMode(nMapMode); + } + else + { + // map against logical inch for non-constrained mapping modes + int cxPerInch = GetDeviceCaps(LOGPIXELSX); + int cyPerInch = GetDeviceCaps(LOGPIXELSY); + ATLASSERT(cxPerInch != 0 && cyPerInch != 0); + lpSize->cx = ::MulDiv(lpSize->cx, cxPerInch, HIMETRIC_INCH); + lpSize->cy = ::MulDiv(lpSize->cy, cyPerInch, HIMETRIC_INCH); + } + } + + void LPtoHIMETRIC(LPSIZE lpSize) const + { + LPtoDP(lpSize); + DPtoHIMETRIC(lpSize); + } + + void HIMETRICtoLP(LPSIZE lpSize) const + { + HIMETRICtoDP(lpSize); + DPtoLP(lpSize); + } +#endif // !_WIN32_WCE + +// Region Functions + BOOL FillRgn(HRGN hRgn, HBRUSH hBrush) + { + ATLASSERT(m_hDC != NULL); + return ::FillRgn(m_hDC, hRgn, hBrush); + } + +#ifndef _WIN32_WCE + BOOL FrameRgn(HRGN hRgn, HBRUSH hBrush, int nWidth, int nHeight) + { + ATLASSERT(m_hDC != NULL); + return ::FrameRgn(m_hDC, hRgn, hBrush, nWidth, nHeight); + } + + BOOL InvertRgn(HRGN hRgn) + { + ATLASSERT(m_hDC != NULL); + return ::InvertRgn(m_hDC, hRgn); + } + + BOOL PaintRgn(HRGN hRgn) + { + ATLASSERT(m_hDC != NULL); + return ::PaintRgn(m_hDC, hRgn); + } +#endif // !_WIN32_WCE + +// Clipping Functions + int GetClipBox(LPRECT lpRect) const + { + ATLASSERT(m_hDC != NULL); + return ::GetClipBox(m_hDC, lpRect); + } + + int GetClipRgn(CRgn& region) const + { + ATLASSERT(m_hDC != NULL); + if(region.IsNull()) + region.CreateRectRgn(0, 0, 0, 0); + + int nRet = ::GetClipRgn(m_hDC, region); + if(nRet != 1) + region.DeleteObject(); + + return nRet; + } + +#ifndef _WIN32_WCE + BOOL PtVisible(int x, int y) const + { + ATLASSERT(m_hDC != NULL); + return ::PtVisible(m_hDC, x, y); + } + + BOOL PtVisible(POINT point) const + { + ATLASSERT(m_hDC != NULL); + return ::PtVisible(m_hDC, point.x, point.y); + } +#endif // !_WIN32_WCE + + BOOL RectVisible(LPCRECT lpRect) const + { + ATLASSERT(m_hDC != NULL); + return ::RectVisible(m_hDC, lpRect); + } + + int SelectClipRgn(HRGN hRgn) + { + ATLASSERT(m_hDC != NULL); + return ::SelectClipRgn(m_hDC, (HRGN)hRgn); + } + + int ExcludeClipRect(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hDC != NULL); + return ::ExcludeClipRect(m_hDC, x1, y1, x2, y2); + } + + int ExcludeClipRect(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::ExcludeClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + +#ifndef _WIN32_WCE + int ExcludeUpdateRgn(HWND hWnd) + { + ATLASSERT(m_hDC != NULL); + return ::ExcludeUpdateRgn(m_hDC, hWnd); + } +#endif // !_WIN32_WCE + + int IntersectClipRect(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hDC != NULL); + return ::IntersectClipRect(m_hDC, x1, y1, x2, y2); + } + + int IntersectClipRect(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::IntersectClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + +#ifndef _WIN32_WCE + int OffsetClipRgn(int x, int y) + { + ATLASSERT(m_hDC != NULL); + return ::OffsetClipRgn(m_hDC, x, y); + } + + int OffsetClipRgn(SIZE size) + { + ATLASSERT(m_hDC != NULL); + return ::OffsetClipRgn(m_hDC, size.cx, size.cy); + } + + int SelectClipRgn(HRGN hRgn, int nMode) + { + ATLASSERT(m_hDC != NULL); + return ::ExtSelectClipRgn(m_hDC, hRgn, nMode); + } +#endif // !_WIN32_WCE + +// Line-Output Functions +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + BOOL GetCurrentPosition(LPPOINT lpPoint) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCurrentPositionEx(m_hDC, lpPoint); + } + + BOOL MoveTo(int x, int y, LPPOINT lpPoint = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::MoveToEx(m_hDC, x, y, lpPoint); + } + + BOOL MoveTo(POINT point, LPPOINT lpPointRet = NULL) + { + ATLASSERT(m_hDC != NULL); + return MoveTo(point.x, point.y, lpPointRet); + } + + BOOL LineTo(int x, int y) + { + ATLASSERT(m_hDC != NULL); + return ::LineTo(m_hDC, x, y); + } + + BOOL LineTo(POINT point) + { + ATLASSERT(m_hDC != NULL); + return LineTo(point.x, point.y); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + +#ifndef _WIN32_WCE + BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) + { + ATLASSERT(m_hDC != NULL); + return ::Arc(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); + } + + BOOL Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd) + { + ATLASSERT(m_hDC != NULL); + return ::Arc(m_hDC, lpRect->left, lpRect->top, + lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, + ptEnd.x, ptEnd.y); + } +#endif // !_WIN32_WCE + + BOOL Polyline(LPPOINT lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::Polyline(m_hDC, lpPoints, nCount); + } + +#ifndef _WIN32_WCE + BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle) + { + ATLASSERT(m_hDC != NULL); + return ::AngleArc(m_hDC, x, y, nRadius, fStartAngle, fSweepAngle); + } + + BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) + { + ATLASSERT(m_hDC != NULL); + return ::ArcTo(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); + } + + BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd) + { + ATLASSERT(m_hDC != NULL); + return ArcTo(lpRect->left, lpRect->top, lpRect->right, + lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); + } + + int GetArcDirection() const + { + ATLASSERT(m_hDC != NULL); + return ::GetArcDirection(m_hDC); + } + + int SetArcDirection(int nArcDirection) + { + ATLASSERT(m_hDC != NULL); + return ::SetArcDirection(m_hDC, nArcDirection); + } + + BOOL PolyDraw(const POINT* lpPoints, const BYTE* lpTypes, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyDraw(m_hDC, lpPoints, lpTypes, nCount); + } + + BOOL PolylineTo(const POINT* lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolylineTo(m_hDC, lpPoints, nCount); + } + + BOOL PolyPolyline(const POINT* lpPoints, + const DWORD* lpPolyPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyPolyline(m_hDC, lpPoints, lpPolyPoints, nCount); + } + + BOOL PolyBezier(const POINT* lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyBezier(m_hDC, lpPoints, nCount); + } + + BOOL PolyBezierTo(const POINT* lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyBezierTo(m_hDC, lpPoints, nCount); + } +#endif // !_WIN32_WCE + +// Simple Drawing Functions + BOOL FillRect(LPCRECT lpRect, HBRUSH hBrush) + { + ATLASSERT(m_hDC != NULL); + return ::FillRect(m_hDC, lpRect, hBrush); + } + + BOOL FillRect(LPCRECT lpRect, int nColorIndex) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + return ::FillRect(m_hDC, lpRect, (HBRUSH)LongToPtr(nColorIndex + 1)); +#else // CE specific + return ::FillRect(m_hDC, lpRect, ::GetSysColorBrush(nColorIndex)); +#endif // _WIN32_WCE + } + +#ifndef _WIN32_WCE + BOOL FrameRect(LPCRECT lpRect, HBRUSH hBrush) + { + ATLASSERT(m_hDC != NULL); + return ::FrameRect(m_hDC, lpRect, hBrush); + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) + BOOL InvertRect(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::InvertRect(m_hDC, lpRect); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) + + BOOL DrawIcon(int x, int y, HICON hIcon) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + return ::DrawIcon(m_hDC, x, y, hIcon); +#else // CE specific + return ::DrawIconEx(m_hDC, x, y, hIcon, 0, 0, 0, NULL, DI_NORMAL); +#endif // _WIN32_WCE + } + + BOOL DrawIcon(POINT point, HICON hIcon) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + return ::DrawIcon(m_hDC, point.x, point.y, hIcon); +#else // CE specific + return ::DrawIconEx(m_hDC, point.x, point.y, hIcon, 0, 0, 0, NULL, DI_NORMAL); +#endif // _WIN32_WCE + } + + BOOL DrawIconEx(int x, int y, HICON hIcon, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawIconEx(m_hDC, x, y, hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); + } + + BOOL DrawIconEx(POINT point, HICON hIcon, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawIconEx(m_hDC, point.x, point.y, hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); + } + +#ifndef _WIN32_WCE + BOOL DrawState(POINT pt, SIZE size, HBITMAP hBitmap, UINT nFlags, HBRUSH hBrush = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hBitmap, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_BITMAP); + } + + BOOL DrawState(POINT pt, SIZE size, HICON hIcon, UINT nFlags, HBRUSH hBrush = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hIcon, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_ICON); + } + + BOOL DrawState(POINT pt, SIZE size, LPCTSTR lpszText, UINT nFlags, BOOL bPrefixText = TRUE, int nTextLen = 0, HBRUSH hBrush = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)lpszText, (WPARAM)nTextLen, pt.x, pt.y, size.cx, size.cy, nFlags | (bPrefixText ? DST_PREFIXTEXT : DST_TEXT)); + } + + BOOL DrawState(POINT pt, SIZE size, DRAWSTATEPROC lpDrawProc, LPARAM lData, UINT nFlags, HBRUSH hBrush = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawState(m_hDC, hBrush, lpDrawProc, lData, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_COMPLEX); + } +#endif // !_WIN32_WCE + +// Ellipse and Polygon Functions +#ifndef _WIN32_WCE + BOOL Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) + { + ATLASSERT(m_hDC != NULL); + return ::Chord(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); + } + + BOOL Chord(LPCRECT lpRect, POINT ptStart, POINT ptEnd) + { + ATLASSERT(m_hDC != NULL); + return ::Chord(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); + } +#endif // !_WIN32_WCE + + void DrawFocusRect(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + ::DrawFocusRect(m_hDC, lpRect); + } + + BOOL Ellipse(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hDC != NULL); + return ::Ellipse(m_hDC, x1, y1, x2, y2); + } + + BOOL Ellipse(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::Ellipse(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + +#ifndef _WIN32_WCE + BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) + { + ATLASSERT(m_hDC != NULL); + return ::Pie(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); + } + + BOOL Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd) + { + ATLASSERT(m_hDC != NULL); + return ::Pie(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); + } +#endif // !_WIN32_WCE + + BOOL Polygon(LPPOINT lpPoints, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::Polygon(m_hDC, lpPoints, nCount); + } + +#ifndef _WIN32_WCE + BOOL PolyPolygon(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount) + { + ATLASSERT(m_hDC != NULL); + return ::PolyPolygon(m_hDC, lpPoints, lpPolyCounts, nCount); + } +#endif // !_WIN32_WCE + + BOOL Rectangle(int x1, int y1, int x2, int y2) + { + ATLASSERT(m_hDC != NULL); + return ::Rectangle(m_hDC, x1, y1, x2, y2); + } + + BOOL Rectangle(LPCRECT lpRect) + { + ATLASSERT(m_hDC != NULL); + return ::Rectangle(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + } + + BOOL RoundRect(int x1, int y1, int x2, int y2, int x3, int y3) + { + ATLASSERT(m_hDC != NULL); + return ::RoundRect(m_hDC, x1, y1, x2, y2, x3, y3); + } + + BOOL RoundRect(LPCRECT lpRect, POINT point) + { + ATLASSERT(m_hDC != NULL); + return ::RoundRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, point.x, point.y); + } + +// Bitmap Functions + BOOL PatBlt(int x, int y, int nWidth, int nHeight, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::PatBlt(m_hDC, x, y, nWidth, nHeight, dwRop); + } + + BOOL BitBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, + int xSrc, int ySrc, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::BitBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, dwRop); + } + + BOOL StretchBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::StretchBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwRop); + } + + COLORREF GetPixel(int x, int y) const + { + ATLASSERT(m_hDC != NULL); + return ::GetPixel(m_hDC, x, y); + } + + COLORREF GetPixel(POINT point) const + { + ATLASSERT(m_hDC != NULL); + return ::GetPixel(m_hDC, point.x, point.y); + } + + COLORREF SetPixel(int x, int y, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixel(m_hDC, x, y, crColor); + } + + COLORREF SetPixel(POINT point, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixel(m_hDC, point.x, point.y, crColor); + } + +#ifndef _WIN32_WCE + BOOL FloodFill(int x, int y, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::FloodFill(m_hDC, x, y, crColor); + } + + BOOL ExtFloodFill(int x, int y, COLORREF crColor, UINT nFillType) + { + ATLASSERT(m_hDC != NULL); + return ::ExtFloodFill(m_hDC, x, y, crColor, nFillType); + } +#endif // !_WIN32_WCE + + BOOL MaskBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, HBITMAP hMaskBitmap, int xMask, int yMask, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::MaskBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, hMaskBitmap, xMask, yMask, dwRop); + } + +#ifndef _WIN32_WCE + BOOL PlgBlt(LPPOINT lpPoint, HDC hSrcDC, int xSrc, int ySrc, int nWidth, int nHeight, HBITMAP hMaskBitmap, int xMask, int yMask) + { + ATLASSERT(m_hDC != NULL); + return ::PlgBlt(m_hDC, lpPoint, hSrcDC, xSrc, ySrc, nWidth, nHeight, hMaskBitmap, xMask, yMask); + } + + BOOL SetPixelV(int x, int y, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixelV(m_hDC, x, y, crColor); + } + + BOOL SetPixelV(POINT point, COLORREF crColor) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixelV(m_hDC, point.x, point.y, crColor); + } +#endif // !_WIN32_WCE + +#if !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE) +#ifndef _WIN32_WCE + BOOL TransparentBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent) + { + ATLASSERT(m_hDC != NULL); + return ::TransparentBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent); + } +#else // CE specific + BOOL TransparentImage(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent) + { + ATLASSERT(m_hDC != NULL); + return ::TransparentImage(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent); + } +#endif // _WIN32_WCE + +#if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420)) + BOOL GradientFill(const PTRIVERTEX pVertices, DWORD nVertices, void* pMeshElements, DWORD nMeshElements, DWORD dwMode) + { + ATLASSERT(m_hDC != NULL); + return ::GradientFill(m_hDC, pVertices, nVertices, pMeshElements, nMeshElements, dwMode); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) + +#if !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500) + BOOL AlphaBlend(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, BLENDFUNCTION bf) + { + ATLASSERT(m_hDC != NULL); + return ::AlphaBlend(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500) +#endif // !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE) + +// Extra bitmap functions + // Helper function for painting a disabled toolbar or menu bitmap + // This function can take either an HBITMAP (for SS) or a DC with + // the bitmap already painted (for cmdbar) + BOOL DitherBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, HBITMAP hBitmap, int xSrc, int ySrc, + HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE), + HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT), + HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW)) + { + ATLASSERT(m_hDC != NULL || hBitmap != NULL); + ATLASSERT(nWidth > 0 && nHeight > 0); + + // Create a generic DC for all BitBlts + CDCHandle dc = (hSrcDC != NULL) ? hSrcDC : ::CreateCompatibleDC(m_hDC); + ATLASSERT(dc.m_hDC != NULL); + if(dc.m_hDC == NULL) + return FALSE; + + // Create a DC for the monochrome DIB section + CDC dcBW = ::CreateCompatibleDC(m_hDC); + ATLASSERT(dcBW.m_hDC != NULL); + if(dcBW.m_hDC == NULL) + { + if(hSrcDC == NULL) + dc.DeleteDC(); + return FALSE; + } + + // Create the monochrome DIB section with a black and white palette + struct RGBBWBITMAPINFO + { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[2]; + }; + + RGBBWBITMAPINFO rgbBWBitmapInfo = + { + { sizeof(BITMAPINFOHEADER), nWidth, nHeight, 1, 1, BI_RGB, 0, 0, 0, 0, 0 }, + { { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 } } + }; + + VOID* pbitsBW; + CBitmap bmpBW = ::CreateDIBSection(dcBW, (LPBITMAPINFO)&rgbBWBitmapInfo, DIB_RGB_COLORS, &pbitsBW, NULL, 0); + ATLASSERT(bmpBW.m_hBitmap != NULL); + if(bmpBW.m_hBitmap == NULL) + { + if(hSrcDC == NULL) + dc.DeleteDC(); + return FALSE; + } + + // Attach the monochrome DIB section and the bitmap to the DCs + HBITMAP hbmOldBW = dcBW.SelectBitmap(bmpBW); + HBITMAP hbmOldDC = NULL; + if(hBitmap != NULL) + hbmOldDC = dc.SelectBitmap(hBitmap); + + // Block: Dark gray removal: we want (128, 128, 128) pixels to become black and not white + { + CDC dcTemp1 = ::CreateCompatibleDC(m_hDC); + CDC dcTemp2 = ::CreateCompatibleDC(m_hDC); + CBitmap bmpTemp1; + bmpTemp1.CreateCompatibleBitmap(dc, nWidth, nHeight); + CBitmap bmpTemp2; + bmpTemp2.CreateBitmap(nWidth, nHeight, 1, 1, NULL); + HBITMAP hOldBmp1 = dcTemp1.SelectBitmap(bmpTemp1); + HBITMAP hOldBmp2 = dcTemp2.SelectBitmap(bmpTemp2); + // Let's copy our image, it will be altered + dcTemp1.BitBlt(0, 0, nWidth, nHeight, dc, xSrc, ySrc, SRCCOPY); + + // All dark gray pixels will become white, the others black + dcTemp1.SetBkColor(RGB(128, 128, 128)); + dcTemp2.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY); + // Do an XOR to set to black these white pixels + dcTemp1.BitBlt(0, 0, nWidth, nHeight, dcTemp2, 0, 0, SRCINVERT); + + // BitBlt the bitmap into the monochrome DIB section + // The DIB section will do a true monochrome conversion + // The magenta background being closer to white will become white + dcBW.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY); + + // Cleanup + dcTemp1.SelectBitmap(hOldBmp1); + dcTemp2.SelectBitmap(hOldBmp2); + } + + // Paint the destination rectangle using hBrushBackground + if(hBrushBackground != NULL) + { + RECT rc = { x, y, x + nWidth, y + nHeight }; + FillRect(&rc, hBrushBackground); + } + + // BitBlt the black bits in the monochrome bitmap into hBrush3DEffect color in the destination DC + // The magic ROP comes from the Charles Petzold's book + HBRUSH hOldBrush = SelectBrush(hBrush3DEffect); + BitBlt(x + 1, y + 1, nWidth, nHeight, dcBW, 0, 0, 0xB8074A); + + // BitBlt the black bits in the monochrome bitmap into hBrushDisabledImage color in the destination DC + SelectBrush(hBrushDisabledImage); + BitBlt(x, y, nWidth, nHeight, dcBW, 0, 0, 0xB8074A); + + SelectBrush(hOldBrush); + dcBW.SelectBitmap(hbmOldBW); + dc.SelectBitmap(hbmOldDC); + + if(hSrcDC == NULL) + dc.DeleteDC(); + + return TRUE; + } + +// Text Functions +#ifndef _WIN32_WCE + BOOL TextOut(int x, int y, LPCTSTR lpszString, int nCount = -1) + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + return ::TextOut(m_hDC, x, y, lpszString, nCount); + } +#endif // !_WIN32_WCE + + BOOL ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, LPCTSTR lpszString, UINT nCount = -1, LPINT lpDxWidths = NULL) + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + return ::ExtTextOut(m_hDC, x, y, nOptions, lpRect, lpszString, nCount, lpDxWidths); + } + +#ifndef _WIN32_WCE + SIZE TabbedTextOut(int x, int y, LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL, int nTabOrigin = 0) + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + LONG lRes = ::TabbedTextOut(m_hDC, x, y, lpszString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin); + SIZE size = { GET_X_LPARAM(lRes), GET_Y_LPARAM(lRes) }; + return size; + } +#endif // !_WIN32_WCE + + int DrawText(LPCTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat) + { + ATLASSERT(m_hDC != NULL); +#ifndef _WIN32_WCE + ATLASSERT((uFormat & DT_MODIFYSTRING) == 0); +#endif // !_WIN32_WCE + return ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat); + } + + int DrawText(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat) + { + ATLASSERT(m_hDC != NULL); + return ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat); + } + +#ifndef _WIN32_WCE + int DrawTextEx(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat, LPDRAWTEXTPARAMS lpDTParams = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::DrawTextEx(m_hDC, lpstrText, cchText, lpRect, uFormat, lpDTParams); + } +#endif // !_WIN32_WCE + +#if (_WIN32_WINNT >= 0x0501) + int DrawShadowText(LPCWSTR lpstrText, int cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset) + { + ATLASSERT(m_hDC != NULL); + // This function is present only if comctl32.dll version 6 is loaded; + // we use LoadLibrary/GetProcAddress to allow apps compiled with + // _WIN32_WINNT >= 0x0501 to run on older Windows/CommCtrl + int nRet = 0; + HMODULE hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll")); + ATLASSERT(hCommCtrlDLL != NULL); + if(hCommCtrlDLL != NULL) + { + typedef int (WINAPI *PFN_DrawShadowText)(HDC hDC, LPCWSTR lpstrText, UINT cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset); + PFN_DrawShadowText pfnDrawShadowText = (PFN_DrawShadowText)::GetProcAddress(hCommCtrlDLL, "DrawShadowText"); + ATLASSERT(pfnDrawShadowText != NULL); // this function requires CommCtrl6 + if(pfnDrawShadowText != NULL) + nRet = pfnDrawShadowText(m_hDC, lpstrText, cchText, lpRect, dwFlags, clrText, clrShadow, xOffset, yOffset); + ::FreeLibrary(hCommCtrlDLL); + } + return nRet; + } +#endif // (_WIN32_WINNT >= 0x0501) + + BOOL GetTextExtent(LPCTSTR lpszString, int nCount, LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + return ::GetTextExtentPoint32(m_hDC, lpszString, nCount, lpSize); + } + + BOOL GetTextExtentExPoint(LPCTSTR lpszString, int cchString, LPSIZE lpSize, int nMaxExtent, LPINT lpnFit = NULL, LPINT alpDx = NULL) + { + ATLASSERT(m_hDC != NULL); + return ::GetTextExtentExPoint(m_hDC, lpszString, cchString, nMaxExtent, lpnFit, alpDx, lpSize); + } + +#ifndef _WIN32_WCE + DWORD GetTabbedTextExtent(LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL) const + { + ATLASSERT(m_hDC != NULL); + if(nCount == -1) + nCount = lstrlen(lpszString); + return ::GetTabbedTextExtent(m_hDC, lpszString, nCount, nTabPositions, lpnTabStopPositions); + } + + BOOL GrayString(HBRUSH hBrush, BOOL (CALLBACK* lpfnOutput)(HDC, LPARAM, int), LPARAM lpData, int nCount, int x, int y, int nWidth, int nHeight) + { + ATLASSERT(m_hDC != NULL); + return ::GrayString(m_hDC, hBrush, (GRAYSTRINGPROC)lpfnOutput, lpData, nCount, x, y, nWidth, nHeight); + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + UINT GetTextAlign() const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextAlign(m_hDC); + } + + UINT SetTextAlign(UINT nFlags) + { + ATLASSERT(m_hDC != NULL); + return ::SetTextAlign(m_hDC, nFlags); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + + int GetTextFace(LPTSTR lpszFacename, int nCount) const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextFace(m_hDC, nCount, lpszFacename); + } + + int GetTextFaceLen() const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextFace(m_hDC, 0, NULL); + } + +#ifndef _ATL_NO_COM +#ifdef _OLEAUTO_H_ + BOOL GetTextFace(BSTR& bstrFace) const + { + USES_CONVERSION; + ATLASSERT(m_hDC != NULL); + ATLASSERT(bstrFace == NULL); + + int nLen = GetTextFaceLen(); + if(nLen == 0) + return FALSE; + + CTempBuffer buff; + LPTSTR lpszText = buff.Allocate(nLen); + if(lpszText == NULL) + return FALSE; + + if(!GetTextFace(lpszText, nLen)) + return FALSE; + + bstrFace = ::SysAllocString(T2OLE(lpszText)); + return (bstrFace != NULL) ? TRUE : FALSE; + } +#endif +#endif // !_ATL_NO_COM + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetTextFace(_CSTRING_NS::CString& strFace) const + { + ATLASSERT(m_hDC != NULL); + + int nLen = GetTextFaceLen(); + if(nLen == 0) + return 0; + + LPTSTR lpstr = strFace.GetBufferSetLength(nLen); + if(lpstr == NULL) + return 0; + int nRet = GetTextFace(lpstr, nLen); + strFace.ReleaseBuffer(); + return nRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics) const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextMetrics(m_hDC, lpMetrics); + } + +#ifndef _WIN32_WCE + int SetTextJustification(int nBreakExtra, int nBreakCount) + { + ATLASSERT(m_hDC != NULL); + return ::SetTextJustification(m_hDC, nBreakExtra, nBreakCount); + } + + int GetTextCharacterExtra() const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextCharacterExtra(m_hDC); + } + + int SetTextCharacterExtra(int nCharExtra) + { + ATLASSERT(m_hDC != NULL); + return ::SetTextCharacterExtra(m_hDC, nCharExtra); + } +#endif // !_WIN32_WCE + +// Advanced Drawing + BOOL DrawEdge(LPRECT lpRect, UINT nEdge, UINT nFlags) + { + ATLASSERT(m_hDC != NULL); + return ::DrawEdge(m_hDC, lpRect, nEdge, nFlags); + } + + BOOL DrawFrameControl(LPRECT lpRect, UINT nType, UINT nState) + { + ATLASSERT(m_hDC != NULL); + return ::DrawFrameControl(m_hDC, lpRect, nType, nState); + } + +// Scrolling Functions + BOOL ScrollDC(int dx, int dy, LPCRECT lpRectScroll, LPCRECT lpRectClip, HRGN hRgnUpdate, LPRECT lpRectUpdate) + { + ATLASSERT(m_hDC != NULL); + return ::ScrollDC(m_hDC, dx, dy, lpRectScroll, lpRectClip, hRgnUpdate, lpRectUpdate); + } + +// Font Functions +#ifndef _WIN32_WCE + BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharWidth(m_hDC, nFirstChar, nLastChar, lpBuffer); + } + + // GetCharWidth32 is not supported under Win9x + BOOL GetCharWidth32(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharWidth32(m_hDC, nFirstChar, nLastChar, lpBuffer); + } + + DWORD SetMapperFlags(DWORD dwFlag) + { + ATLASSERT(m_hDC != NULL); + return ::SetMapperFlags(m_hDC, dwFlag); + } + + BOOL GetAspectRatioFilter(LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetAspectRatioFilterEx(m_hDC, lpSize); + } + + BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABC lpabc) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharABCWidths(m_hDC, nFirstChar, nLastChar, lpabc); + } + + DWORD GetFontData(DWORD dwTable, DWORD dwOffset, LPVOID lpData, DWORD cbData) const + { + ATLASSERT(m_hDC != NULL); + return ::GetFontData(m_hDC, dwTable, dwOffset, lpData, cbData); + } + + int GetKerningPairs(int nPairs, LPKERNINGPAIR lpkrnpair) const + { + ATLASSERT(m_hDC != NULL); + return ::GetKerningPairs(m_hDC, nPairs, lpkrnpair); + } + + UINT GetOutlineTextMetrics(UINT cbData, LPOUTLINETEXTMETRIC lpotm) const + { + ATLASSERT(m_hDC != NULL); + return ::GetOutlineTextMetrics(m_hDC, cbData, lpotm); + } + + DWORD GetGlyphOutline(UINT nChar, UINT nFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpBuffer, const MAT2* lpmat2) const + { + ATLASSERT(m_hDC != NULL); + return ::GetGlyphOutline(m_hDC, nChar, nFormat, lpgm, cbBuffer, lpBuffer, lpmat2); + } + + BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABCFLOAT lpABCF) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharABCWidthsFloat(m_hDC, nFirstChar, nLastChar, lpABCF); + } + + BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, float* lpFloatBuffer) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharWidthFloat(m_hDC, nFirstChar, nLastChar, lpFloatBuffer); + } +#endif // !_WIN32_WCE + +// Printer/Device Escape Functions +#ifndef _WIN32_WCE + int Escape(int nEscape, int nCount, LPCSTR lpszInData, LPVOID lpOutData) + { + ATLASSERT(m_hDC != NULL); + return ::Escape(m_hDC, nEscape, nCount, lpszInData, lpOutData); + } +#endif // !_WIN32_WCE + + int Escape(int nEscape, int nInputSize, LPCSTR lpszInputData, + int nOutputSize, LPSTR lpszOutputData) + { + ATLASSERT(m_hDC != NULL); + return ::ExtEscape(m_hDC, nEscape, nInputSize, lpszInputData, nOutputSize, lpszOutputData); + } + +#ifndef _WIN32_WCE + int DrawEscape(int nEscape, int nInputSize, LPCSTR lpszInputData) + { + ATLASSERT(m_hDC != NULL); + return ::DrawEscape(m_hDC, nEscape, nInputSize, lpszInputData); + } +#endif // !_WIN32_WCE + + // Escape helpers +#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc)) + int StartDoc(LPCTSTR lpszDocName) // old Win3.0 version + { + DOCINFO di = { 0 }; + di.cbSize = sizeof(DOCINFO); + di.lpszDocName = lpszDocName; + return StartDoc(&di); + } + + int StartDoc(LPDOCINFO lpDocInfo) + { + ATLASSERT(m_hDC != NULL); + return ::StartDoc(m_hDC, lpDocInfo); + } + + int StartPage() + { + ATLASSERT(m_hDC != NULL); + return ::StartPage(m_hDC); + } + + int EndPage() + { + ATLASSERT(m_hDC != NULL); + return ::EndPage(m_hDC); + } + + int SetAbortProc(BOOL (CALLBACK* lpfn)(HDC, int)) + { + ATLASSERT(m_hDC != NULL); + return ::SetAbortProc(m_hDC, (ABORTPROC)lpfn); + } + + int AbortDoc() + { + ATLASSERT(m_hDC != NULL); + return ::AbortDoc(m_hDC); + } + + int EndDoc() + { + ATLASSERT(m_hDC != NULL); + return ::EndDoc(m_hDC); + } +#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc)) + +// MetaFile Functions +#ifndef _WIN32_WCE + BOOL PlayMetaFile(HMETAFILE hMF) + { + ATLASSERT(m_hDC != NULL); + if(::GetDeviceCaps(m_hDC, TECHNOLOGY) == DT_METAFILE) + { + // playing metafile in metafile, just use core windows API + return ::PlayMetaFile(m_hDC, hMF); + } + + // for special playback, lParam == pDC + return ::EnumMetaFile(m_hDC, hMF, EnumMetaFileProc, (LPARAM)this); + } + + BOOL PlayMetaFile(HENHMETAFILE hEnhMetaFile, LPCRECT lpBounds) + { + ATLASSERT(m_hDC != NULL); + return ::PlayEnhMetaFile(m_hDC, hEnhMetaFile, lpBounds); + } + + BOOL AddMetaFileComment(UINT nDataSize, const BYTE* pCommentData) // can be used for enhanced metafiles only + { + ATLASSERT(m_hDC != NULL); + return ::GdiComment(m_hDC, nDataSize, pCommentData); + } + + // Special handling for metafile playback + static int CALLBACK EnumMetaFileProc(HDC hDC, HANDLETABLE* pHandleTable, METARECORD* pMetaRec, int nHandles, LPARAM lParam) + { + CDCHandle* pDC = (CDCHandle*)lParam; + + switch (pMetaRec->rdFunction) + { + case META_SETMAPMODE: + pDC->SetMapMode((int)(short)pMetaRec->rdParm[0]); + break; + case META_SETWINDOWEXT: + pDC->SetWindowExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SETWINDOWORG: + pDC->SetWindowOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SETVIEWPORTEXT: + pDC->SetViewportExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SETVIEWPORTORG: + pDC->SetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SCALEWINDOWEXT: + pDC->ScaleWindowExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2], + (int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SCALEVIEWPORTEXT: + pDC->ScaleViewportExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2], + (int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_OFFSETVIEWPORTORG: + pDC->OffsetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); + break; + case META_SAVEDC: + pDC->SaveDC(); + break; + case META_RESTOREDC: + pDC->RestoreDC((int)(short)pMetaRec->rdParm[0]); + break; + case META_SETBKCOLOR: + pDC->SetBkColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]); + break; + case META_SETTEXTCOLOR: + pDC->SetTextColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]); + break; + + // need to watch out for SelectObject(HFONT), for custom font mapping + case META_SELECTOBJECT: + { + HGDIOBJ hObject = pHandleTable->objectHandle[pMetaRec->rdParm[0]]; + UINT nObjType = ::GetObjectType(hObject); + if(nObjType == 0) + { + // object type is unknown, determine if it is a font + HFONT hStockFont = (HFONT)::GetStockObject(SYSTEM_FONT); + HFONT hFontOld = (HFONT)::SelectObject(pDC->m_hDC, hStockFont); + HGDIOBJ hObjOld = ::SelectObject(pDC->m_hDC, hObject); + if(hObjOld == hStockFont) + { + // got the stock object back, so must be selecting a font + pDC->SelectFont((HFONT)hObject); + break; // don't play the default record + } + else + { + // didn't get the stock object back, so restore everything + ::SelectObject(pDC->m_hDC, hFontOld); + ::SelectObject(pDC->m_hDC, hObjOld); + } + // and fall through to PlayMetaFileRecord... + } + else if(nObjType == OBJ_FONT) + { + // play back as CDCHandle::SelectFont(HFONT) + pDC->SelectFont((HFONT)hObject); + break; // don't play the default record + } + } + // fall through... + + default: + ::PlayMetaFileRecord(hDC, pHandleTable, pMetaRec, nHandles); + break; + } + + return 1; + } +#endif // !_WIN32_WCE + +// Path Functions +#ifndef _WIN32_WCE + BOOL AbortPath() + { + ATLASSERT(m_hDC != NULL); + return ::AbortPath(m_hDC); + } + + BOOL BeginPath() + { + ATLASSERT(m_hDC != NULL); + return ::BeginPath(m_hDC); + } + + BOOL CloseFigure() + { + ATLASSERT(m_hDC != NULL); + return ::CloseFigure(m_hDC); + } + + BOOL EndPath() + { + ATLASSERT(m_hDC != NULL); + return ::EndPath(m_hDC); + } + + BOOL FillPath() + { + ATLASSERT(m_hDC != NULL); + return ::FillPath(m_hDC); + } + + BOOL FlattenPath() + { + ATLASSERT(m_hDC != NULL); + return ::FlattenPath(m_hDC); + } + + BOOL StrokeAndFillPath() + { + ATLASSERT(m_hDC != NULL); + return ::StrokeAndFillPath(m_hDC); + } + + BOOL StrokePath() + { + ATLASSERT(m_hDC != NULL); + return ::StrokePath(m_hDC); + } + + BOOL WidenPath() + { + ATLASSERT(m_hDC != NULL); + return ::WidenPath(m_hDC); + } + + BOOL GetMiterLimit(PFLOAT pfMiterLimit) const + { + ATLASSERT(m_hDC != NULL); + return ::GetMiterLimit(m_hDC, pfMiterLimit); + } + + BOOL SetMiterLimit(float fMiterLimit) + { + ATLASSERT(m_hDC != NULL); + return ::SetMiterLimit(m_hDC, fMiterLimit, NULL); + } + + int GetPath(LPPOINT lpPoints, LPBYTE lpTypes, int nCount) const + { + ATLASSERT(m_hDC != NULL); + return ::GetPath(m_hDC, lpPoints, lpTypes, nCount); + } + + BOOL SelectClipPath(int nMode) + { + ATLASSERT(m_hDC != NULL); + return ::SelectClipPath(m_hDC, nMode); + } +#endif // !_WIN32_WCE + +// Misc Helper Functions + static CBrushHandle PASCAL GetHalftoneBrush() + { + HBRUSH halftoneBrush = NULL; + WORD grayPattern[8]; + for(int i = 0; i < 8; i++) + grayPattern[i] = (WORD)(0x5555 << (i & 1)); + HBITMAP grayBitmap = CreateBitmap(8, 8, 1, 1, &grayPattern); + if(grayBitmap != NULL) + { + halftoneBrush = ::CreatePatternBrush(grayBitmap); + DeleteObject(grayBitmap); + } + return CBrushHandle(halftoneBrush); + } + + void DrawDragRect(LPCRECT lpRect, SIZE size, LPCRECT lpRectLast, SIZE sizeLast, HBRUSH hBrush = NULL, HBRUSH hBrushLast = NULL) + { + // first, determine the update region and select it + CRgn rgnOutside; + rgnOutside.CreateRectRgnIndirect(lpRect); + RECT rect = *lpRect; + ::InflateRect(&rect, -size.cx, -size.cy); + ::IntersectRect(&rect, &rect, lpRect); + CRgn rgnInside; + rgnInside.CreateRectRgnIndirect(&rect); + CRgn rgnNew; + rgnNew.CreateRectRgn(0, 0, 0, 0); + rgnNew.CombineRgn(rgnOutside, rgnInside, RGN_XOR); + + HBRUSH hBrushOld = NULL; + CBrush brushHalftone; + if(hBrush == NULL) + brushHalftone = hBrush = CDCHandle::GetHalftoneBrush(); + if(hBrushLast == NULL) + hBrushLast = hBrush; + + CRgn rgnLast; + CRgn rgnUpdate; + if(lpRectLast != NULL) + { + // find difference between new region and old region + rgnLast.CreateRectRgn(0, 0, 0, 0); + rgnOutside.SetRectRgn(lpRectLast->left, lpRectLast->top, lpRectLast->right, lpRectLast->bottom); + rect = *lpRectLast; + ::InflateRect(&rect, -sizeLast.cx, -sizeLast.cy); + ::IntersectRect(&rect, &rect, lpRectLast); + rgnInside.SetRectRgn(rect.left, rect.top, rect.right, rect.bottom); + rgnLast.CombineRgn(rgnOutside, rgnInside, RGN_XOR); + + // only diff them if brushes are the same + if(hBrush == hBrushLast) + { + rgnUpdate.CreateRectRgn(0, 0, 0, 0); + rgnUpdate.CombineRgn(rgnLast, rgnNew, RGN_XOR); + } + } + if(hBrush != hBrushLast && lpRectLast != NULL) + { + // brushes are different -- erase old region first + SelectClipRgn(rgnLast); + GetClipBox(&rect); + hBrushOld = SelectBrush(hBrushLast); + PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); + SelectBrush(hBrushOld); + hBrushOld = NULL; + } + + // draw into the update/new region + SelectClipRgn(rgnUpdate.IsNull() ? rgnNew : rgnUpdate); + GetClipBox(&rect); + hBrushOld = SelectBrush(hBrush); + PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); + + // cleanup DC + if(hBrushOld != NULL) + SelectBrush(hBrushOld); + SelectClipRgn(NULL); + } + + void FillSolidRect(LPCRECT lpRect, COLORREF clr) + { + ATLASSERT(m_hDC != NULL); + + COLORREF clrOld = ::SetBkColor(m_hDC, clr); + ATLASSERT(clrOld != CLR_INVALID); + if(clrOld != CLR_INVALID) + { + ::ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL); + ::SetBkColor(m_hDC, clrOld); + } + } + + void FillSolidRect(int x, int y, int cx, int cy, COLORREF clr) + { + ATLASSERT(m_hDC != NULL); + + RECT rect = { x, y, x + cx, y + cy }; + FillSolidRect(&rect, clr); + } + + void Draw3dRect(LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight) + { + Draw3dRect(lpRect->left, lpRect->top, lpRect->right - lpRect->left, + lpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight); + } + + void Draw3dRect(int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight) + { + FillSolidRect(x, y, cx - 1, 1, clrTopLeft); + FillSolidRect(x, y, 1, cy - 1, clrTopLeft); + FillSolidRect(x + cx, y, -1, cy, clrBottomRight); + FillSolidRect(x, y + cy, cx, -1, clrBottomRight); + } + +// DIB support +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) + int SetDIBitsToDevice(int x, int y, DWORD dwWidth, DWORD dwHeight, int xSrc, int ySrc, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse) + { + ATLASSERT(m_hDC != NULL); + return ::SetDIBitsToDevice(m_hDC, x, y, dwWidth, dwHeight, xSrc, ySrc, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) + +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + int StretchDIBits(int x, int y, int nWidth, int nHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse, DWORD dwRop) + { + ATLASSERT(m_hDC != NULL); + return ::StretchDIBits(m_hDC, x, y, nWidth, nHeight, xSrc, ySrc, nSrcWidth, nSrcHeight, lpvBits, lpbmi, uColorUse, dwRop); + } + + UINT GetDIBColorTable(UINT uStartIndex, UINT cEntries, RGBQUAD* pColors) const + { + ATLASSERT(m_hDC != NULL); + return ::GetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors); + } + + UINT SetDIBColorTable(UINT uStartIndex, UINT cEntries, CONST RGBQUAD* pColors) + { + ATLASSERT(m_hDC != NULL); + return ::SetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors); + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + +// OpenGL support +#if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) + int ChoosePixelFormat(CONST PIXELFORMATDESCRIPTOR* ppfd) + { + ATLASSERT(m_hDC != NULL); + return ::ChoosePixelFormat(m_hDC, ppfd); + } + + int DescribePixelFormat(int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd) + { + ATLASSERT(m_hDC != NULL); + return ::DescribePixelFormat(m_hDC, iPixelFormat, nBytes, ppfd); + } + + int GetPixelFormat() const + { + ATLASSERT(m_hDC != NULL); + return ::GetPixelFormat(m_hDC); + } + + BOOL SetPixelFormat(int iPixelFormat, CONST PIXELFORMATDESCRIPTOR* ppfd) + { + ATLASSERT(m_hDC != NULL); + return ::SetPixelFormat(m_hDC, iPixelFormat, ppfd); + } + + BOOL SwapBuffers() + { + ATLASSERT(m_hDC != NULL); + return ::SwapBuffers(m_hDC); + } + + HGLRC wglCreateContext() + { + ATLASSERT(m_hDC != NULL); + return ::wglCreateContext(m_hDC); + } + + HGLRC wglCreateLayerContext(int iLayerPlane) + { + ATLASSERT(m_hDC != NULL); + return ::wglCreateLayerContext(m_hDC, iLayerPlane); + } + + BOOL wglMakeCurrent(HGLRC hglrc) + { + ATLASSERT(m_hDC != NULL); + return ::wglMakeCurrent(m_hDC, hglrc); + } + + BOOL wglUseFontBitmaps(DWORD dwFirst, DWORD dwCount, DWORD listBase) + { + ATLASSERT(m_hDC != NULL); + return ::wglUseFontBitmaps(m_hDC, dwFirst, dwCount, listBase); + } + + BOOL wglUseFontOutlines(DWORD dwFirst, DWORD dwCount, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf) + { + ATLASSERT(m_hDC != NULL); + return ::wglUseFontOutlines(m_hDC, dwFirst, dwCount, listBase, deviation, extrusion, format, lpgmf); + } + + BOOL wglDescribeLayerPlane(int iPixelFormat, int iLayerPlane, UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd) + { + ATLASSERT(m_hDC != NULL); + return ::wglDescribeLayerPlane(m_hDC, iPixelFormat, iLayerPlane, nBytes, plpd); + } + + int wglSetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, CONST COLORREF* pclr) + { + ATLASSERT(m_hDC != NULL); + return ::wglSetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr); + } + + int wglGetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, COLORREF* pclr) + { + ATLASSERT(m_hDC != NULL); + return ::wglGetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr); + } + + BOOL wglRealizeLayerPalette(int iLayerPlane, BOOL bRealize) + { + ATLASSERT(m_hDC != NULL); + return ::wglRealizeLayerPalette(m_hDC, iLayerPlane, bRealize); + } + + BOOL wglSwapLayerBuffers(UINT uPlanes) + { + ATLASSERT(m_hDC != NULL); + return ::wglSwapLayerBuffers(m_hDC, uPlanes); + } +#endif // !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) + +// New for Windows 2000 only +#if (_WIN32_WINNT >= 0x0500) + COLORREF GetDCPenColor() const + { + ATLASSERT(m_hDC != NULL); + return ::GetDCPenColor(m_hDC); + } + + COLORREF SetDCPenColor(COLORREF clr) + { + ATLASSERT(m_hDC != NULL); + return ::SetDCPenColor(m_hDC, clr); + } + + COLORREF GetDCBrushColor() const + { + ATLASSERT(m_hDC != NULL); + return ::GetDCBrushColor(m_hDC); + } + + COLORREF SetDCBrushColor(COLORREF clr) + { + ATLASSERT(m_hDC != NULL); + return ::SetDCBrushColor(m_hDC, clr); + } + +#ifndef _WIN32_WCE + DWORD GetFontUnicodeRanges(LPGLYPHSET lpgs) const + { + ATLASSERT(m_hDC != NULL); + return ::GetFontUnicodeRanges(m_hDC, lpgs); + } +#endif // !_WIN32_WCE + + DWORD GetGlyphIndices(LPCTSTR lpstr, int cch, LPWORD pgi, DWORD dwFlags) const + { + ATLASSERT(m_hDC != NULL); + return ::GetGlyphIndices(m_hDC, lpstr, cch, pgi, dwFlags); + } + + BOOL GetTextExtentPointI(LPWORD pgiIn, int cgi, LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextExtentPointI(m_hDC, pgiIn, cgi, lpSize); + } + + BOOL GetTextExtentExPointI(LPWORD pgiIn, int cgi, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize) const + { + ATLASSERT(m_hDC != NULL); + return ::GetTextExtentExPointI(m_hDC, pgiIn, cgi, nMaxExtent, lpnFit, alpDx, lpSize); + } + + BOOL GetCharWidthI(UINT giFirst, UINT cgi, LPWORD pgi, LPINT lpBuffer) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharWidthI(m_hDC, giFirst, cgi, pgi, lpBuffer); + } + + BOOL GetCharABCWidthsI(UINT giFirst, UINT cgi, LPWORD pgi, LPABC lpabc) const + { + ATLASSERT(m_hDC != NULL); + return ::GetCharABCWidthsI(m_hDC, giFirst, cgi, pgi, lpabc); + } +#endif // (_WIN32_WINNT >= 0x0500) + +// New for Windows 2000 and Windows 98 +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + BOOL ColorCorrectPalette(HPALETTE hPalette, DWORD dwFirstEntry, DWORD dwNumOfEntries) + { + ATLASSERT(m_hDC != NULL); + return ::ColorCorrectPalette(m_hDC, hPalette, dwFirstEntry, dwNumOfEntries); + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) +}; + +typedef CDCT CDCHandle; +typedef CDCT CDC; + + +/////////////////////////////////////////////////////////////////////////////// +// CDC Helpers + +class CPaintDC : public CDC +{ +public: +// Data members + HWND m_hWnd; + PAINTSTRUCT m_ps; + +// Constructor/destructor + CPaintDC(HWND hWnd) + { + ATLASSERT(::IsWindow(hWnd)); + m_hWnd = hWnd; + m_hDC = ::BeginPaint(hWnd, &m_ps); + } + + ~CPaintDC() + { + ATLASSERT(m_hDC != NULL); + ATLASSERT(::IsWindow(m_hWnd)); + ::EndPaint(m_hWnd, &m_ps); + Detach(); + } +}; + +class CClientDC : public CDC +{ +public: +// Data members + HWND m_hWnd; + +// Constructor/destructor + CClientDC(HWND hWnd) + { + ATLASSERT(hWnd == NULL || ::IsWindow(hWnd)); + m_hWnd = hWnd; + m_hDC = ::GetDC(hWnd); + } + + ~CClientDC() + { + ATLASSERT(m_hDC != NULL); + ::ReleaseDC(m_hWnd, Detach()); + } +}; + +class CWindowDC : public CDC +{ +public: +// Data members + HWND m_hWnd; + +// Constructor/destructor + CWindowDC(HWND hWnd) + { + ATLASSERT(hWnd == NULL || ::IsWindow(hWnd)); + m_hWnd = hWnd; + m_hDC = ::GetWindowDC(hWnd); + } + + ~CWindowDC() + { + ATLASSERT(m_hDC != NULL); + ::ReleaseDC(m_hWnd, Detach()); + } +}; + +class CMemoryDC : public CDC +{ +public: +// Data members + HDC m_hDCOriginal; + RECT m_rcPaint; + CBitmap m_bmp; + HBITMAP m_hBmpOld; + +// Constructor/destructor + CMemoryDC(HDC hDC, RECT& rcPaint) : m_hDCOriginal(hDC), m_hBmpOld(NULL) + { + m_rcPaint = rcPaint; + CreateCompatibleDC(m_hDCOriginal); + ATLASSERT(m_hDC != NULL); + m_bmp.CreateCompatibleBitmap(m_hDCOriginal, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top); + ATLASSERT(m_bmp.m_hBitmap != NULL); + m_hBmpOld = SelectBitmap(m_bmp); + SetViewportOrg(-m_rcPaint.left, -m_rcPaint.top); + } + + ~CMemoryDC() + { + ::BitBlt(m_hDCOriginal, m_rcPaint.left, m_rcPaint.top, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top, m_hDC, m_rcPaint.left, m_rcPaint.top, SRCCOPY); + SelectBitmap(m_hBmpOld); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Enhanced metafile support + +#ifndef _WIN32_WCE + +class CEnhMetaFileInfo +{ +public: +// Data members + HENHMETAFILE m_hEMF; + BYTE* m_pBits; + TCHAR* m_pDesc; + ENHMETAHEADER m_header; + PIXELFORMATDESCRIPTOR m_pfd; + +// Constructor/destructor + CEnhMetaFileInfo(HENHMETAFILE hEMF) : m_pBits(NULL), m_pDesc(NULL), m_hEMF(hEMF) + { } + + ~CEnhMetaFileInfo() + { + delete [] m_pBits; + delete [] m_pDesc; + } + +// Operations + BYTE* GetEnhMetaFileBits() + { + ATLASSERT(m_hEMF != NULL); + UINT nBytes = ::GetEnhMetaFileBits(m_hEMF, 0, NULL); + delete [] m_pBits; + m_pBits = NULL; + ATLTRY(m_pBits = new BYTE[nBytes]); + if (m_pBits != NULL) + ::GetEnhMetaFileBits(m_hEMF, nBytes, m_pBits); + return m_pBits; + } + + LPTSTR GetEnhMetaFileDescription() + { + ATLASSERT(m_hEMF != NULL); + UINT nLen = ::GetEnhMetaFileDescription(m_hEMF, 0, NULL); + delete [] m_pDesc; + m_pDesc = NULL; + ATLTRY(m_pDesc = new TCHAR[nLen]); + if (m_pDesc != NULL) + nLen = ::GetEnhMetaFileDescription(m_hEMF, nLen, m_pDesc); + return m_pDesc; + } + + ENHMETAHEADER* GetEnhMetaFileHeader() + { + ATLASSERT(m_hEMF != NULL); + memset(&m_header, 0, sizeof(m_header)); + m_header.iType = EMR_HEADER; + m_header.nSize = sizeof(ENHMETAHEADER); + UINT n = ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), &m_header); + return (n != 0) ? &m_header : NULL; + } + + PIXELFORMATDESCRIPTOR* GetEnhMetaFilePixelFormat() + { + ATLASSERT(m_hEMF != NULL); + memset(&m_pfd, 0, sizeof(m_pfd)); + UINT n = ::GetEnhMetaFilePixelFormat(m_hEMF, sizeof(m_pfd), &m_pfd); + return (n != 0) ? &m_pfd : NULL; + } +}; + + +template +class CEnhMetaFileT +{ +public: +// Data members + HENHMETAFILE m_hEMF; + +// Constructor/destructor + CEnhMetaFileT(HENHMETAFILE hEMF = NULL) : m_hEMF(hEMF) + { + } + + ~CEnhMetaFileT() + { + if(t_bManaged && m_hEMF != NULL) + DeleteObject(); + } + +// Operations + CEnhMetaFileT& operator =(HENHMETAFILE hEMF) + { + Attach(hEMF); + return *this; + } + + void Attach(HENHMETAFILE hEMF) + { + if(t_bManaged && m_hEMF != NULL && m_hEMF != hEMF) + DeleteObject(); + m_hEMF = hEMF; + } + + HENHMETAFILE Detach() + { + HENHMETAFILE hEMF = m_hEMF; + m_hEMF = NULL; + return hEMF; + } + + operator HENHMETAFILE() const { return m_hEMF; } + + bool IsNull() const { return (m_hEMF == NULL); } + + BOOL DeleteObject() + { + ATLASSERT(m_hEMF != NULL); + BOOL bRet = ::DeleteEnhMetaFile(m_hEMF); + m_hEMF = NULL; + return bRet; + } + + UINT GetEnhMetaFileBits(UINT cbBuffer, LPBYTE lpbBuffer) const + { + ATLASSERT(m_hEMF != NULL); + return ::GetEnhMetaFileBits(m_hEMF, cbBuffer, lpbBuffer); + } + + UINT GetEnhMetaFileDescription(UINT cchBuffer, LPTSTR lpszDescription) const + { + ATLASSERT(m_hEMF != NULL); + return ::GetEnhMetaFileDescription(m_hEMF, cchBuffer, lpszDescription); + } + + UINT GetEnhMetaFileHeader(LPENHMETAHEADER lpemh) const + { + ATLASSERT(m_hEMF != NULL); + lpemh->iType = EMR_HEADER; + lpemh->nSize = sizeof(ENHMETAHEADER); + return ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), lpemh); + } + + UINT GetEnhMetaFilePaletteEntries(UINT cEntries, LPPALETTEENTRY lppe) const + { + ATLASSERT(m_hEMF != NULL); + return ::GetEnhMetaFilePaletteEntries(m_hEMF, cEntries, lppe); + } + + UINT GetEnhMetaFilePixelFormat(DWORD cbBuffer, PIXELFORMATDESCRIPTOR* ppfd) const + { + ATLASSERT(m_hEMF != NULL); + return ::GetEnhMetaFilePixelFormat(m_hEMF, cbBuffer, ppfd); + } +}; + +typedef CEnhMetaFileT CEnhMetaFileHandle; +typedef CEnhMetaFileT CEnhMetaFile; + + +class CEnhMetaFileDC : public CDC +{ +public: +// Constructor/destructor + CEnhMetaFileDC() + { + } + + CEnhMetaFileDC(HDC hdc, LPCRECT lpRect) + { + Create(hdc, NULL, lpRect, NULL); + ATLASSERT(m_hDC != NULL); + } + + CEnhMetaFileDC(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription) + { + Create(hdcRef, lpFilename, lpRect, lpDescription); + ATLASSERT(m_hDC != NULL); + } + + ~CEnhMetaFileDC() + { + HENHMETAFILE hEMF = Close(); + if (hEMF != NULL) + ::DeleteEnhMetaFile(hEMF); + } + +// Operations + void Create(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription) + { + ATLASSERT(m_hDC == NULL); + m_hDC = ::CreateEnhMetaFile(hdcRef, lpFilename, lpRect, lpDescription); + } + + HENHMETAFILE Close() + { + HENHMETAFILE hEMF = NULL; + if (m_hDC != NULL) + { + hEMF = ::CloseEnhMetaFile(m_hDC); + m_hDC = NULL; + } + return hEMF; + } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// WinCE compatible clipboard CF_DIB format support functions + +#ifndef _WTL_NO_DIB16 + +#define DIBINFO16_BITFIELDS { 31744, 992, 31 } + +// DIBINFO16 - To avoid color table problems in WinCE we only create this type of Dib +struct DIBINFO16 // a BITMAPINFO with 2 additional color bitfields +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[3]; + + DIBINFO16(SIZE size) + { + BITMAPINFOHEADER bmih = { sizeof(BITMAPINFOHEADER), size.cx, size.cy, + 1, 16, BI_BITFIELDS, 2 * size.cx * size.cy , 0, 0, 3 }; + DWORD dw[3] = DIBINFO16_BITFIELDS ; + + bmiHeader = bmih; + memcpy(bmiColors, dw, 3 * sizeof(DWORD)); + } +}; + + +// AtlxxxDibxxx minimal packed DIB implementation and helpers to copy and paste CF_DIB + +inline bool AtlIsDib16(LPBITMAPINFOHEADER pbmih) +{ + return (pbmih->biBitCount == 16) && (pbmih->biCompression == BI_BITFIELDS); +} + +inline int AtlGetDibColorTableSize(LPBITMAPINFOHEADER pbmih) +{ + switch (pbmih->biBitCount) + { + case 2: + case 4: + case 8: + return pbmih->biClrUsed ? pbmih->biClrUsed : 1 << pbmih->biBitCount; + case 24: + break; + case 16: + case 32: + return pbmih->biCompression == BI_BITFIELDS ? 3 : 0; + default: + ATLASSERT(FALSE); // should never come here + } + + return 0; +} + +inline int AtlGetDibNumColors(LPBITMAPINFOHEADER pbmih) +{ + switch (pbmih->biBitCount) + { + case 2: + case 4: + case 8: + if (pbmih->biClrUsed) + return pbmih->biClrUsed; + else + break; + case 16: + if (pbmih->biCompression == BI_BITFIELDS ) + return 1 << 15; + else + break; + case 24: + break; + case 32: + if (pbmih->biCompression == BI_BITFIELDS ) + return 1 << 24; + else + break; + default: + ATLASSERT(FALSE); + } + + return 1 << pbmih->biBitCount; +} + +inline HBITMAP AtlGetDibBitmap(LPBITMAPINFO pbmi) +{ + HBITMAP hbm = NULL; + CDC dc(NULL); + void * pBits = NULL; + + LPBYTE pDibBits = (LPBYTE)pbmi + sizeof(BITMAPINFOHEADER) + AtlGetDibColorTableSize(&pbmi->bmiHeader) * sizeof(RGBQUAD); + if (hbm = CreateDIBSection(dc, pbmi, DIB_RGB_COLORS, &pBits, NULL, NULL)) + memcpy(pBits, pDibBits, pbmi->bmiHeader.biSizeImage); + + return hbm; +} + +inline HBITMAP AtlCopyBitmap(HBITMAP hbm , SIZE sizeDst, bool bAsBitmap = false) +{ + CDC hdcSrc = CreateCompatibleDC(NULL); + CDC hdcDst = CreateCompatibleDC(NULL); + + CBitmapHandle hbmOld = NULL, hbmOld2 = NULL, bmSrc = hbm; + + CBitmap bmNew = NULL; + + SIZE sizeSrc = { 0 }; + bmSrc.GetSize(sizeSrc); + + hbmOld = hdcSrc.SelectBitmap(bmSrc); + + if (bAsBitmap) + { + bmNew.CreateCompatibleBitmap(hdcSrc, sizeDst.cx, sizeDst.cy); + } + else + { + DIBINFO16 dib16(sizeDst); + LPVOID pBits = NULL; + bmNew = CreateDIBSection(hdcDst, (const BITMAPINFO*)&dib16, DIB_RGB_COLORS, &pBits, NULL, NULL); + } + + ATLASSERT(!bmNew.IsNull()); + + hbmOld2 = hdcDst.SelectBitmap(bmNew); + BOOL bOK = FALSE; + + if ((sizeDst.cx == sizeSrc.cx) && (sizeDst.cy == sizeSrc.cy)) + bOK = hdcDst.BitBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, SRCCOPY); + else + bOK = hdcDst.StretchBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, sizeSrc.cx, sizeSrc.cy, SRCCOPY); + + hdcSrc.SelectBitmap(hbmOld); + hdcDst.SelectBitmap(hbmOld2); + + if (bOK == FALSE) + bmNew.DeleteObject(); + + return bmNew.Detach(); +} + +inline HLOCAL AtlCreatePackedDib16(HBITMAP hbm, SIZE size) +{ + DIBSECTION ds = { 0 }; + LPBYTE pDib = NULL; + bool bCopied = false; + + bool bOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds); + if ((bOK == FALSE) || (ds.dsBm.bmBits == NULL) || (AtlIsDib16(&ds.dsBmih) == FALSE) || + (ds.dsBmih.biWidth != size.cx ) || (ds.dsBmih.biHeight != size.cy )) + { + if ((hbm = AtlCopyBitmap(hbm, size)) != NULL) + { + bCopied = true; + bOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds); + } + else + { + bOK = FALSE; + } + } + + if((bOK == TRUE) && (AtlIsDib16(&ds.dsBmih) == TRUE) && (ds.dsBm.bmBits != NULL)) + { + pDib = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage); + if (pDib != NULL) + { + memcpy(pDib , &ds.dsBmih, sizeof(DIBINFO16)); + memcpy(pDib + sizeof(DIBINFO16), ds.dsBm.bmBits, ds.dsBmih.biSizeImage); + } + } + + if (bCopied == true) + DeleteObject(hbm); + + return (HLOCAL)pDib; +} + +inline bool AtlSetClipboardDib16(HBITMAP hbm, SIZE size, HWND hWnd) +{ + ATLASSERT(::IsWindow(hWnd)); + BOOL bOK = OpenClipboard(hWnd); + if (bOK == TRUE) + { + if ((bOK = EmptyClipboard()) == TRUE) + { + HLOCAL hDib = AtlCreatePackedDib16(hbm, size); + if (hDib != NULL) + { + bOK = SetClipboardData(CF_DIB, hDib) != NULL; + if (bOK == FALSE) + LocalFree(hDib); + } + else + { + bOK = FALSE; + } + } + CloseClipboard(); + } + + return bOK == TRUE; +} + +inline HBITMAP AtlGetClipboardDib(HWND hWnd) +{ + ATLASSERT(::IsWindow(hWnd) == TRUE); + HBITMAP hbm = NULL; + if (OpenClipboard(hWnd) == TRUE) + { + LPBITMAPINFO pbmi = (LPBITMAPINFO)GetClipboardData(CF_DIB); + if (pbmi != NULL) + hbm = AtlGetDibBitmap(pbmi); + CloseClipboard(); + } + + return hbm; +} + +#endif // _WTL_NO_DIB16 + +}; // namespace WTL + +#endif // __ATLGDI_H__ diff --git a/wtl/wtl/include/atlmisc.h b/wtl/wtl/include/atlmisc.h new file mode 100644 index 00000000..70c8745f --- /dev/null +++ b/wtl/wtl/include/atlmisc.h @@ -0,0 +1,4021 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLMISC_H__ +#define __ATLMISC_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlmisc.h requires atlapp.h to be included first +#endif + + +#ifdef _ATL_TMP_NO_CSTRING + #define _WTL_NO_CSTRING +#endif + +#if defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING) + #error Conflicting options - both _WTL_USE_CSTRING and _WTL_NO_CSTRING are defined +#endif // defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING) + +#if !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING) + #define _WTL_USE_CSTRING +#endif // !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING) + +#ifndef _WTL_NO_CSTRING + #if defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT) + #error Cannot use CString floating point formatting with _ATL_MIN_CRT defined + #endif // defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT) +#endif // !_WTL_NO_CSTRING + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CSize +// CPoint +// CRect +// CString +// +// CRecentDocumentListBase +// CRecentDocumentList +// CFindFile +// +// Global functions: +// AtlLoadAccelerators() +// AtlLoadMenu() +// AtlLoadBitmap() +// AtlLoadSysBitmap() +// AtlLoadCursor() +// AtlLoadSysCursor() +// AtlLoadIcon() +// AtlLoadSysIcon() +// AtlLoadBitmapImage() +// AtlLoadCursorImage() +// AtlLoadIconImage() +// AtlLoadSysBitmapImage() +// AtlLoadSysCursorImage() +// AtlLoadSysIconImage() +// AtlLoadString() +// +// AtlGetStockPen() +// AtlGetStockBrush() +// AtlGetStockFont() +// AtlGetStockPalette() +// +// AtlCompactPath() + + +namespace WTL +{ + +#ifndef _WTL_NO_WTYPES + +// forward declarations +class CSize; +class CPoint; +class CRect; + +/////////////////////////////////////////////////////////////////////////////// +// CSize - Wrapper for Windows SIZE structure. + +class CSize : public SIZE +{ +public: +// Constructors + CSize() + { + cx = 0; + cy = 0; + } + + CSize(int initCX, int initCY) + { + cx = initCX; + cy = initCY; + } + + CSize(SIZE initSize) + { + *(SIZE*)this = initSize; + } + + CSize(POINT initPt) + { + *(POINT*)this = initPt; + } + + CSize(DWORD dwSize) + { + cx = (short)LOWORD(dwSize); + cy = (short)HIWORD(dwSize); + } + +// Operations + BOOL operator ==(SIZE size) const + { + return (cx == size.cx && cy == size.cy); + } + + BOOL operator !=(SIZE size) const + { + return (cx != size.cx || cy != size.cy); + } + + void operator +=(SIZE size) + { + cx += size.cx; + cy += size.cy; + } + + void operator -=(SIZE size) + { + cx -= size.cx; + cy -= size.cy; + } + + void SetSize(int CX, int CY) + { + cx = CX; + cy = CY; + } + +// Operators returning CSize values + CSize operator +(SIZE size) const + { + return CSize(cx + size.cx, cy + size.cy); + } + + CSize operator -(SIZE size) const + { + return CSize(cx - size.cx, cy - size.cy); + } + + CSize operator -() const + { + return CSize(-cx, -cy); + } + +// Operators returning CPoint values + CPoint operator +(POINT point) const; + CPoint operator -(POINT point) const; + +// Operators returning CRect values + CRect operator +(const RECT* lpRect) const; + CRect operator -(const RECT* lpRect) const; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPoint - Wrapper for Windows POINT structure. + +class CPoint : public POINT +{ +public: +// Constructors + CPoint() + { + x = 0; + y = 0; + } + + CPoint(int initX, int initY) + { + x = initX; + y = initY; + } + + CPoint(POINT initPt) + { + *(POINT*)this = initPt; + } + + CPoint(SIZE initSize) + { + *(SIZE*)this = initSize; + } + + CPoint(DWORD dwPoint) + { + x = (short)LOWORD(dwPoint); + y = (short)HIWORD(dwPoint); + } + +// Operations + void Offset(int xOffset, int yOffset) + { + x += xOffset; + y += yOffset; + } + + void Offset(POINT point) + { + x += point.x; + y += point.y; + } + + void Offset(SIZE size) + { + x += size.cx; + y += size.cy; + } + + BOOL operator ==(POINT point) const + { + return (x == point.x && y == point.y); + } + + BOOL operator !=(POINT point) const + { + return (x != point.x || y != point.y); + } + + void operator +=(SIZE size) + { + x += size.cx; + y += size.cy; + } + + void operator -=(SIZE size) + { + x -= size.cx; + y -= size.cy; + } + + void operator +=(POINT point) + { + x += point.x; + y += point.y; + } + + void operator -=(POINT point) + { + x -= point.x; + y -= point.y; + } + + void SetPoint(int X, int Y) + { + x = X; + y = Y; + } + +// Operators returning CPoint values + CPoint operator +(SIZE size) const + { + return CPoint(x + size.cx, y + size.cy); + } + + CPoint operator -(SIZE size) const + { + return CPoint(x - size.cx, y - size.cy); + } + + CPoint operator -() const + { + return CPoint(-x, -y); + } + + CPoint operator +(POINT point) const + { + return CPoint(x + point.x, y + point.y); + } + +// Operators returning CSize values + CSize operator -(POINT point) const + { + return CSize(x - point.x, y - point.y); + } + +// Operators returning CRect values + CRect operator +(const RECT* lpRect) const; + CRect operator -(const RECT* lpRect) const; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CRect - Wrapper for Windows RECT structure. + +class CRect : public RECT +{ +public: +// Constructors + CRect() + { + left = 0; + top = 0; + right = 0; + bottom = 0; + } + + CRect(int l, int t, int r, int b) + { + left = l; + top = t; + right = r; + bottom = b; + } + + CRect(const RECT& srcRect) + { + ::CopyRect(this, &srcRect); + } + + CRect(LPCRECT lpSrcRect) + { + ::CopyRect(this, lpSrcRect); + } + + CRect(POINT point, SIZE size) + { + right = (left = point.x) + size.cx; + bottom = (top = point.y) + size.cy; + } + + CRect(POINT topLeft, POINT bottomRight) + { + left = topLeft.x; + top = topLeft.y; + right = bottomRight.x; + bottom = bottomRight.y; + } + +// Attributes (in addition to RECT members) + int Width() const + { + return right - left; + } + + int Height() const + { + return bottom - top; + } + + CSize Size() const + { + return CSize(right - left, bottom - top); + } + + CPoint& TopLeft() + { + return *((CPoint*)this); + } + + CPoint& BottomRight() + { + return *((CPoint*)this + 1); + } + + const CPoint& TopLeft() const + { + return *((CPoint*)this); + } + + const CPoint& BottomRight() const + { + return *((CPoint*)this + 1); + } + + CPoint CenterPoint() const + { + return CPoint((left + right) / 2, (top + bottom) / 2); + } + + // convert between CRect and LPRECT/LPCRECT (no need for &) + operator LPRECT() + { + return this; + } + + operator LPCRECT() const + { + return this; + } + + BOOL IsRectEmpty() const + { + return ::IsRectEmpty(this); + } + + BOOL IsRectNull() const + { + return (left == 0 && right == 0 && top == 0 && bottom == 0); + } + + BOOL PtInRect(POINT point) const + { + return ::PtInRect(this, point); + } + +// Operations + void SetRect(int x1, int y1, int x2, int y2) + { + ::SetRect(this, x1, y1, x2, y2); + } + + void SetRect(POINT topLeft, POINT bottomRight) + { + ::SetRect(this, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); + } + + void SetRectEmpty() + { + ::SetRectEmpty(this); + } + + void CopyRect(LPCRECT lpSrcRect) + { + ::CopyRect(this, lpSrcRect); + } + + BOOL EqualRect(LPCRECT lpRect) const + { + return ::EqualRect(this, lpRect); + } + + void InflateRect(int x, int y) + { + ::InflateRect(this, x, y); + } + + void InflateRect(SIZE size) + { + ::InflateRect(this, size.cx, size.cy); + } + + void InflateRect(LPCRECT lpRect) + { + left -= lpRect->left; + top -= lpRect->top; + right += lpRect->right; + bottom += lpRect->bottom; + } + + void InflateRect(int l, int t, int r, int b) + { + left -= l; + top -= t; + right += r; + bottom += b; + } + + void DeflateRect(int x, int y) + { + ::InflateRect(this, -x, -y); + } + + void DeflateRect(SIZE size) + { + ::InflateRect(this, -size.cx, -size.cy); + } + + void DeflateRect(LPCRECT lpRect) + { + left += lpRect->left; + top += lpRect->top; + right -= lpRect->right; + bottom -= lpRect->bottom; + } + + void DeflateRect(int l, int t, int r, int b) + { + left += l; + top += t; + right -= r; + bottom -= b; + } + + void OffsetRect(int x, int y) + { + ::OffsetRect(this, x, y); + } + void OffsetRect(SIZE size) + { + ::OffsetRect(this, size.cx, size.cy); + } + + void OffsetRect(POINT point) + { + ::OffsetRect(this, point.x, point.y); + } + + void NormalizeRect() + { + int nTemp; + if (left > right) + { + nTemp = left; + left = right; + right = nTemp; + } + if (top > bottom) + { + nTemp = top; + top = bottom; + bottom = nTemp; + } + } + + // absolute position of rectangle + void MoveToY(int y) + { + bottom = Height() + y; + top = y; + } + + void MoveToX(int x) + { + right = Width() + x; + left = x; + } + + void MoveToXY(int x, int y) + { + MoveToX(x); + MoveToY(y); + } + + void MoveToXY(POINT pt) + { + MoveToX(pt.x); + MoveToY(pt.y); + } + + // operations that fill '*this' with result + BOOL IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2) + { + return ::IntersectRect(this, lpRect1, lpRect2); + } + + BOOL UnionRect(LPCRECT lpRect1, LPCRECT lpRect2) + { + return ::UnionRect(this, lpRect1, lpRect2); + } + + BOOL SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2) + { + return ::SubtractRect(this, lpRectSrc1, lpRectSrc2); + } + +// Additional Operations + void operator =(const RECT& srcRect) + { + ::CopyRect(this, &srcRect); + } + + BOOL operator ==(const RECT& rect) const + { + return ::EqualRect(this, &rect); + } + + BOOL operator !=(const RECT& rect) const + { + return !::EqualRect(this, &rect); + } + + void operator +=(POINT point) + { + ::OffsetRect(this, point.x, point.y); + } + + void operator +=(SIZE size) + { + ::OffsetRect(this, size.cx, size.cy); + } + + void operator +=(LPCRECT lpRect) + { + InflateRect(lpRect); + } + + void operator -=(POINT point) + { + ::OffsetRect(this, -point.x, -point.y); + } + + void operator -=(SIZE size) + { + ::OffsetRect(this, -size.cx, -size.cy); + } + + void operator -=(LPCRECT lpRect) + { + DeflateRect(lpRect); + } + + void operator &=(const RECT& rect) + { + ::IntersectRect(this, this, &rect); + } + + void operator |=(const RECT& rect) + { + ::UnionRect(this, this, &rect); + } + +// Operators returning CRect values + CRect operator +(POINT pt) const + { + CRect rect(*this); + ::OffsetRect(&rect, pt.x, pt.y); + return rect; + } + + CRect operator -(POINT pt) const + { + CRect rect(*this); + ::OffsetRect(&rect, -pt.x, -pt.y); + return rect; + } + + CRect operator +(LPCRECT lpRect) const + { + CRect rect(this); + rect.InflateRect(lpRect); + return rect; + } + + CRect operator +(SIZE size) const + { + CRect rect(*this); + ::OffsetRect(&rect, size.cx, size.cy); + return rect; + } + + CRect operator -(SIZE size) const + { + CRect rect(*this); + ::OffsetRect(&rect, -size.cx, -size.cy); + return rect; + } + + CRect operator -(LPCRECT lpRect) const + { + CRect rect(this); + rect.DeflateRect(lpRect); + return rect; + } + + CRect operator &(const RECT& rect2) const + { + CRect rect; + ::IntersectRect(&rect, this, &rect2); + return rect; + } + + CRect operator |(const RECT& rect2) const + { + CRect rect; + ::UnionRect(&rect, this, &rect2); + return rect; + } + + CRect MulDiv(int nMultiplier, int nDivisor) const + { + return CRect( + ::MulDiv(left, nMultiplier, nDivisor), + ::MulDiv(top, nMultiplier, nDivisor), + ::MulDiv(right, nMultiplier, nDivisor), + ::MulDiv(bottom, nMultiplier, nDivisor)); + } +}; + + +// CSize implementation + +inline CPoint CSize::operator +(POINT point) const +{ return CPoint(cx + point.x, cy + point.y); } + +inline CPoint CSize::operator -(POINT point) const +{ return CPoint(cx - point.x, cy - point.y); } + +inline CRect CSize::operator +(const RECT* lpRect) const +{ return CRect(lpRect) + *this; } + +inline CRect CSize::operator -(const RECT* lpRect) const +{ return CRect(lpRect) - *this; } + + +// CPoint implementation + +inline CRect CPoint::operator +(const RECT* lpRect) const +{ return CRect(lpRect) + *this; } + +inline CRect CPoint::operator -(const RECT* lpRect) const +{ return CRect(lpRect) - *this; } + +#endif // !_WTL_NO_WTYPES + + +// WTL::CSize or ATL::CSize scalar operators + +#if !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__)) + +template +inline CSize operator *(SIZE s, Num n) +{ + return CSize((int)(s.cx * n), (int)(s.cy * n)); +}; + +template +inline void operator *=(SIZE & s, Num n) +{ + s = s * n; +}; + +template +inline CSize operator /(SIZE s, Num n) +{ + return CSize((int)(s.cx / n), (int)(s.cy / n)); +}; + +template +inline void operator /=(SIZE & s, Num n) +{ + s = s / n; +}; + +#endif // !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__)) + + +/////////////////////////////////////////////////////////////////////////////// +// CString - String class + +#ifndef _WTL_NO_CSTRING + +struct CStringData +{ + long nRefs; // reference count + int nDataLength; + int nAllocLength; + // TCHAR data[nAllocLength] + + TCHAR* data() + { return (TCHAR*)(this + 1); } +}; + +// Globals + +// For an empty string, m_pchData will point here +// (note: avoids special case of checking for NULL m_pchData) +// empty string data (and locked) +_declspec(selectany) int rgInitData[] = { -1, 0, 0, 0 }; +_declspec(selectany) CStringData* _atltmpDataNil = (CStringData*)&rgInitData; +_declspec(selectany) LPCTSTR _atltmpPchNil = (LPCTSTR)(((BYTE*)&rgInitData) + sizeof(CStringData)); + + +class CString +{ +public: +// Constructors + CString() + { + Init(); + } + + CString(const CString& stringSrc) + { + ATLASSERT(stringSrc.GetData()->nRefs != 0); + if (stringSrc.GetData()->nRefs >= 0) + { + ATLASSERT(stringSrc.GetData() != _atltmpDataNil); + m_pchData = stringSrc.m_pchData; + InterlockedIncrement(&GetData()->nRefs); + } + else + { + Init(); + *this = stringSrc.m_pchData; + } + } + + CString(TCHAR ch, int nRepeat = 1) + { + ATLASSERT(!_istlead(ch)); // can't create a lead byte string + Init(); + if (nRepeat >= 1) + { + if(AllocBuffer(nRepeat)) + { +#ifdef _UNICODE + for (int i = 0; i < nRepeat; i++) + m_pchData[i] = ch; +#else + memset(m_pchData, ch, nRepeat); +#endif + } + } + } + + CString(LPCTSTR lpsz) + { + Init(); + if (lpsz != NULL && HIWORD(lpsz) == NULL) + { + UINT nID = LOWORD((DWORD_PTR)lpsz); + if (!LoadString(nID)) + ATLTRACE2(atlTraceUI, 0, _T("Warning: implicit LoadString(%u) in CString failed\n"), nID); + } + else + { + int nLen = SafeStrlen(lpsz); + if (nLen != 0) + { + if(AllocBuffer(nLen)) + SecureHelper::memcpy_x(m_pchData, (nLen + 1) * sizeof(TCHAR), lpsz, nLen * sizeof(TCHAR)); + } + } + } + +#ifdef _UNICODE + CString(LPCSTR lpsz) + { + Init(); +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0; +#else + int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0; +#endif + if (nSrcLen != 0) + { + if(AllocBuffer(nSrcLen)) + { + _mbstowcsz(m_pchData, lpsz, nSrcLen + 1); + ReleaseBuffer(); + } + } + } +#else // !_UNICODE + CString(LPCWSTR lpsz) + { + Init(); + int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0; + if (nSrcLen != 0) + { + if(AllocBuffer(nSrcLen * 2)) + { + _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1); + ReleaseBuffer(); + } + } + } +#endif // !_UNICODE + + CString(LPCTSTR lpch, int nLength) + { + Init(); + if (nLength != 0) + { + if(AllocBuffer(nLength)) + SecureHelper::memcpy_x(m_pchData, (nLength + 1) * sizeof(TCHAR), lpch, nLength * sizeof(TCHAR)); + } + } + +#ifdef _UNICODE + CString(LPCSTR lpsz, int nLength) + { + Init(); + if (nLength != 0) + { + if(AllocBuffer(nLength)) + { + int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength + 1); + ReleaseBuffer((n >= 0) ? n : -1); + } + } + } +#else // !_UNICODE + CString(LPCWSTR lpsz, int nLength) + { + Init(); + if (nLength != 0) + { + if(((nLength * 2) > nLength) && AllocBuffer(nLength * 2)) + { + int n = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nLength, m_pchData, (nLength * 2) + 1, NULL, NULL); + ReleaseBuffer((n >= 0) ? n : -1); + } + } + } +#endif // !_UNICODE + + CString(const unsigned char* lpsz) + { + Init(); + *this = (LPCSTR)lpsz; + } + +// Attributes & Operations + int GetLength() const // as an array of characters + { + return GetData()->nDataLength; + } + + BOOL IsEmpty() const + { + return GetData()->nDataLength == 0; + } + + void Empty() // free up the data + { + if (GetData()->nDataLength == 0) + return; + + if (GetData()->nRefs >= 0) + Release(); + else + *this = _T(""); + + ATLASSERT(GetData()->nDataLength == 0); + ATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0); + } + + TCHAR GetAt(int nIndex) const // 0 based + { + ATLASSERT(nIndex >= 0); + ATLASSERT(nIndex < GetData()->nDataLength); + return m_pchData[nIndex]; + } + + TCHAR operator [](int nIndex) const // same as GetAt + { + // same as GetAt + ATLASSERT(nIndex >= 0); + ATLASSERT(nIndex < GetData()->nDataLength); + return m_pchData[nIndex]; + } + + void SetAt(int nIndex, TCHAR ch) + { + ATLASSERT(nIndex >= 0); + ATLASSERT(nIndex < GetData()->nDataLength); + + CopyBeforeWrite(); + m_pchData[nIndex] = ch; + } + + operator LPCTSTR() const // as a C string + { + return m_pchData; + } + + // overloaded assignment + CString& operator =(const CString& stringSrc) + { + if (m_pchData != stringSrc.m_pchData) + { + if ((GetData()->nRefs < 0 && GetData() != _atltmpDataNil) || stringSrc.GetData()->nRefs < 0) + { + // actual copy necessary since one of the strings is locked + AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData); + } + else + { + // can just copy references around + Release(); + ATLASSERT(stringSrc.GetData() != _atltmpDataNil); + m_pchData = stringSrc.m_pchData; + InterlockedIncrement(&GetData()->nRefs); + } + } + return *this; + } + + CString& operator =(TCHAR ch) + { + ATLASSERT(!_istlead(ch)); // can't set single lead byte + AssignCopy(1, &ch); + return *this; + } + +#ifdef _UNICODE + CString& operator =(char ch) + { + *this = (TCHAR)ch; + return *this; + } +#endif + + CString& operator =(LPCTSTR lpsz) + { + ATLASSERT(lpsz == NULL || _IsValidString(lpsz)); + AssignCopy(SafeStrlen(lpsz), lpsz); + return *this; + } + +#ifdef _UNICODE + CString& operator =(LPCSTR lpsz) + { +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0; +#else + int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0; +#endif + if(AllocBeforeWrite(nSrcLen)) + { + _mbstowcsz(m_pchData, lpsz, nSrcLen + 1); + ReleaseBuffer(); + } + return *this; + } +#else // !_UNICODE + CString& operator =(LPCWSTR lpsz) + { + int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0; + if(AllocBeforeWrite(nSrcLen * 2)) + { + _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1); + ReleaseBuffer(); + } + return *this; + } +#endif // !_UNICODE + + CString& operator =(const unsigned char* lpsz) + { + *this = (LPCSTR)lpsz; + return *this; + } + + // string concatenation + CString& operator +=(const CString& string) + { + ConcatInPlace(string.GetData()->nDataLength, string.m_pchData); + return *this; + } + + CString& operator +=(TCHAR ch) + { + ConcatInPlace(1, &ch); + return *this; + } + +#ifdef _UNICODE + CString& operator +=(char ch) + { + *this += (TCHAR)ch; + return *this; + } +#endif + + CString& operator +=(LPCTSTR lpsz) + { + ATLASSERT(lpsz == NULL || _IsValidString(lpsz)); + ConcatInPlace(SafeStrlen(lpsz), lpsz); + return *this; + } + + friend CString __stdcall operator +(const CString& string1, const CString& string2); + friend CString __stdcall operator +(const CString& string, TCHAR ch); + friend CString __stdcall operator +(TCHAR ch, const CString& string); +#ifdef _UNICODE + friend CString __stdcall operator +(const CString& string, char ch); + friend CString __stdcall operator +(char ch, const CString& string); +#endif + friend CString __stdcall operator +(const CString& string, LPCTSTR lpsz); + friend CString __stdcall operator +(LPCTSTR lpsz, const CString& string); + + // string comparison + int Compare(LPCTSTR lpsz) const // straight character (MBCS/Unicode aware) + { + return _cstrcmp(m_pchData, lpsz); + } + + int CompareNoCase(LPCTSTR lpsz) const // ignore case (MBCS/Unicode aware) + { + return _cstrcmpi(m_pchData, lpsz); + } + +#ifndef _WIN32_WCE + // CString::Collate is often slower than Compare but is MBSC/Unicode + // aware as well as locale-sensitive with respect to sort order. + int Collate(LPCTSTR lpsz) const // NLS aware + { + return _cstrcoll(m_pchData, lpsz); + } + + int CollateNoCase(LPCTSTR lpsz) const // ignore case + { + return _cstrcolli(m_pchData, lpsz); + } +#endif // !_WIN32_WCE + + // simple sub-string extraction + CString Mid(int nFirst, int nCount) const + { + // out-of-bounds requests return sensible things + if (nFirst < 0) + nFirst = 0; + if (nCount < 0) + nCount = 0; + + if (nFirst + nCount > GetData()->nDataLength) + nCount = GetData()->nDataLength - nFirst; + if (nFirst > GetData()->nDataLength) + nCount = 0; + + CString dest; + AllocCopy(dest, nCount, nFirst, 0); + return dest; + } + + CString Mid(int nFirst) const + { + return Mid(nFirst, GetData()->nDataLength - nFirst); + } + + CString Left(int nCount) const + { + if (nCount < 0) + nCount = 0; + else if (nCount > GetData()->nDataLength) + nCount = GetData()->nDataLength; + + CString dest; + AllocCopy(dest, nCount, 0, 0); + return dest; + } + + CString Right(int nCount) const + { + if (nCount < 0) + nCount = 0; + else if (nCount > GetData()->nDataLength) + nCount = GetData()->nDataLength; + + CString dest; + AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0); + return dest; + } + + CString SpanIncluding(LPCTSTR lpszCharSet) const // strspn equivalent + { + ATLASSERT(_IsValidString(lpszCharSet)); + return Left(_cstrspn(m_pchData, lpszCharSet)); + } + + CString SpanExcluding(LPCTSTR lpszCharSet) const // strcspn equivalent + { + ATLASSERT(_IsValidString(lpszCharSet)); + return Left(_cstrcspn(m_pchData, lpszCharSet)); + } + + // upper/lower/reverse conversion + void MakeUpper() + { + CopyBeforeWrite(); + CharUpper(m_pchData); + } + + void MakeLower() + { + CopyBeforeWrite(); + CharLower(m_pchData); + } + + void MakeReverse() + { + CopyBeforeWrite(); + _cstrrev(m_pchData); + } + + // trimming whitespace (either side) + void TrimRight() + { + CopyBeforeWrite(); + + // find beginning of trailing spaces by starting at beginning (DBCS aware) + LPTSTR lpsz = m_pchData; + LPTSTR lpszLast = NULL; + while (*lpsz != _T('\0')) + { + if (_cstrisspace(*lpsz)) + { + if (lpszLast == NULL) + lpszLast = lpsz; + } + else + { + lpszLast = NULL; + } + lpsz = ::CharNext(lpsz); + } + + if (lpszLast != NULL) + { + // truncate at trailing space start + *lpszLast = _T('\0'); + GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData); + } + } + + void TrimLeft() + { + CopyBeforeWrite(); + + // find first non-space character + LPCTSTR lpsz = m_pchData; + while (_cstrisspace(*lpsz)) + lpsz = ::CharNext(lpsz); + + // fix up data and length + int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData); + SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR)); + GetData()->nDataLength = nDataLength; + } + + // remove continuous occurrences of chTarget starting from right + void TrimRight(TCHAR chTarget) + { + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + CopyBeforeWrite(); + LPTSTR lpsz = m_pchData; + LPTSTR lpszLast = NULL; + + while (*lpsz != _T('\0')) + { + if (*lpsz == chTarget) + { + if (lpszLast == NULL) + lpszLast = lpsz; + } + else + lpszLast = NULL; + lpsz = ::CharNext(lpsz); + } + + if (lpszLast != NULL) + { + // truncate at left-most matching character + *lpszLast = _T('\0'); + GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData); + } + } + + // remove continuous occcurrences of characters in passed string, starting from right + void TrimRight(LPCTSTR lpszTargetList) + { + // find beginning of trailing matches by starting at beginning (DBCS aware) + + CopyBeforeWrite(); + LPTSTR lpsz = m_pchData; + LPTSTR lpszLast = NULL; + + while (*lpsz != _T('\0')) + { + TCHAR* pNext = ::CharNext(lpsz); + if(pNext > lpsz + 1) + { + if (_cstrchr_db(lpszTargetList, *lpsz, *(lpsz + 1)) != NULL) + { + if (lpszLast == NULL) + lpszLast = lpsz; + } + else + { + lpszLast = NULL; + } + } + else + { + if (_cstrchr(lpszTargetList, *lpsz) != NULL) + { + if (lpszLast == NULL) + lpszLast = lpsz; + } + else + { + lpszLast = NULL; + } + } + + lpsz = pNext; + } + + if (lpszLast != NULL) + { + // truncate at left-most matching character + *lpszLast = _T('\0'); + GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData); + } + } + + // remove continuous occurrences of chTarget starting from left + void TrimLeft(TCHAR chTarget) + { + // find first non-matching character + + CopyBeforeWrite(); + LPCTSTR lpsz = m_pchData; + + while (chTarget == *lpsz) + lpsz = ::CharNext(lpsz); + + if (lpsz != m_pchData) + { + // fix up data and length + int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData); + SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR)); + GetData()->nDataLength = nDataLength; + } + } + + // remove continuous occcurrences of characters in passed string, starting from left + void TrimLeft(LPCTSTR lpszTargets) + { + // if we're not trimming anything, we're not doing any work + if (SafeStrlen(lpszTargets) == 0) + return; + + CopyBeforeWrite(); + LPCTSTR lpsz = m_pchData; + + while (*lpsz != _T('\0')) + { + TCHAR* pNext = ::CharNext(lpsz); + if(pNext > lpsz + 1) + { + if (_cstrchr_db(lpszTargets, *lpsz, *(lpsz + 1)) == NULL) + break; + } + else + { + if (_cstrchr(lpszTargets, *lpsz) == NULL) + break; + } + lpsz = pNext; + } + + if (lpsz != m_pchData) + { + // fix up data and length + int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData); + SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR)); + GetData()->nDataLength = nDataLength; + } + } + + // advanced manipulation + // replace occurrences of chOld with chNew + int Replace(TCHAR chOld, TCHAR chNew) + { + int nCount = 0; + + // short-circuit the nop case + if (chOld != chNew) + { + // otherwise modify each character that matches in the string + CopyBeforeWrite(); + LPTSTR psz = m_pchData; + LPTSTR pszEnd = psz + GetData()->nDataLength; + while (psz < pszEnd) + { + // replace instances of the specified character only + if (*psz == chOld) + { + *psz = chNew; + nCount++; + } + psz = ::CharNext(psz); + } + } + return nCount; + } + + // replace occurrences of substring lpszOld with lpszNew; + // empty lpszNew removes instances of lpszOld + int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew) + { + // can't have empty or NULL lpszOld + + int nSourceLen = SafeStrlen(lpszOld); + if (nSourceLen == 0) + return 0; + int nReplacementLen = SafeStrlen(lpszNew); + + // loop once to figure out the size of the result string + int nCount = 0; + LPTSTR lpszStart = m_pchData; + LPTSTR lpszEnd = m_pchData + GetData()->nDataLength; + LPTSTR lpszTarget = NULL; + while (lpszStart < lpszEnd) + { + while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL) + { + nCount++; + lpszStart = lpszTarget + nSourceLen; + } + lpszStart += lstrlen(lpszStart) + 1; + } + + // if any changes were made, make them + if (nCount > 0) + { + CopyBeforeWrite(); + + // if the buffer is too small, just allocate a new buffer (slow but sure) + int nOldLength = GetData()->nDataLength; + int nNewLength = nOldLength + (nReplacementLen - nSourceLen) * nCount; + if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1) + { + CStringData* pOldData = GetData(); + LPTSTR pstr = m_pchData; + if(!AllocBuffer(nNewLength)) + return -1; + SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, pOldData->nDataLength * sizeof(TCHAR)); + CString::Release(pOldData); + } + // else, we just do it in-place + lpszStart = m_pchData; + lpszEnd = m_pchData + GetData()->nDataLength; + + // loop again to actually do the work + while (lpszStart < lpszEnd) + { + while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL) + { + int nBalance = nOldLength - ((int)(DWORD_PTR)(lpszTarget - m_pchData) + nSourceLen); + int cchBuffLen = GetData()->nAllocLength - (int)(DWORD_PTR)(lpszTarget - m_pchData); + SecureHelper::memmove_x(lpszTarget + nReplacementLen, (cchBuffLen - nReplacementLen + 1) * sizeof(TCHAR), lpszTarget + nSourceLen, nBalance * sizeof(TCHAR)); + SecureHelper::memcpy_x(lpszTarget, (cchBuffLen + 1) * sizeof(TCHAR), lpszNew, nReplacementLen * sizeof(TCHAR)); + lpszStart = lpszTarget + nReplacementLen; + lpszStart[nBalance] = _T('\0'); + nOldLength += (nReplacementLen - nSourceLen); + } + lpszStart += lstrlen(lpszStart) + 1; + } + ATLASSERT(m_pchData[nNewLength] == _T('\0')); + GetData()->nDataLength = nNewLength; + } + + return nCount; + } + + // remove occurrences of chRemove + int Remove(TCHAR chRemove) + { + CopyBeforeWrite(); + + LPTSTR pstrSource = m_pchData; + LPTSTR pstrDest = m_pchData; + LPTSTR pstrEnd = m_pchData + GetData()->nDataLength; + + while (pstrSource < pstrEnd) + { + if (*pstrSource != chRemove) + { + *pstrDest = *pstrSource; + pstrDest = ::CharNext(pstrDest); + } + pstrSource = ::CharNext(pstrSource); + } + *pstrDest = _T('\0'); + int nCount = (int)(DWORD_PTR)(pstrSource - pstrDest); + GetData()->nDataLength -= nCount; + + return nCount; + } + + // insert character at zero-based index; concatenates if index is past end of string + int Insert(int nIndex, TCHAR ch) + { + CopyBeforeWrite(); + + if (nIndex < 0) + nIndex = 0; + + int nNewLength = GetData()->nDataLength; + if (nIndex > nNewLength) + nIndex = nNewLength; + nNewLength++; + + if (GetData()->nAllocLength < nNewLength) + { + CStringData* pOldData = GetData(); + LPTSTR pstr = m_pchData; + if(!AllocBuffer(nNewLength)) + return -1; + SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR)); + CString::Release(pOldData); + } + + // move existing bytes down + SecureHelper::memmove_x(m_pchData + nIndex + 1, (GetData()->nAllocLength - nIndex) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex) * sizeof(TCHAR)); + m_pchData[nIndex] = ch; + GetData()->nDataLength = nNewLength; + + return nNewLength; + } + + // insert substring at zero-based index; concatenates if index is past end of string + int Insert(int nIndex, LPCTSTR pstr) + { + if (nIndex < 0) + nIndex = 0; + + int nInsertLength = SafeStrlen(pstr); + int nNewLength = GetData()->nDataLength; + if (nInsertLength > 0) + { + CopyBeforeWrite(); + if (nIndex > nNewLength) + nIndex = nNewLength; + nNewLength += nInsertLength; + + if (GetData()->nAllocLength < nNewLength) + { + CStringData* pOldData = GetData(); + LPTSTR pstr = m_pchData; + if(!AllocBuffer(nNewLength)) + return -1; + SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR)); + CString::Release(pOldData); + } + + // move existing bytes down + SecureHelper::memmove_x(m_pchData + nIndex + nInsertLength, (GetData()->nAllocLength + 1 - nIndex - nInsertLength) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex - nInsertLength + 1) * sizeof(TCHAR)); + SecureHelper::memcpy_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), pstr, nInsertLength * sizeof(TCHAR)); + GetData()->nDataLength = nNewLength; + } + + return nNewLength; + } + + // delete nCount characters starting at zero-based index + int Delete(int nIndex, int nCount = 1) + { + if (nIndex < 0) + nIndex = 0; + int nLength = GetData()->nDataLength; + if (nCount > 0 && nIndex < nLength) + { + if((nIndex + nCount) > nLength) + nCount = nLength - nIndex; + CopyBeforeWrite(); + int nBytesToCopy = nLength - (nIndex + nCount) + 1; + + SecureHelper::memmove_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR)); + nLength -= nCount; + GetData()->nDataLength = nLength; + } + + return nLength; + } + + // searching (return starting index, or -1 if not found) + // look for a single character match + int Find(TCHAR ch) const // like "C" strchr + { + return Find(ch, 0); + } + + int ReverseFind(TCHAR ch) const + { + // find last single character + LPCTSTR lpsz = _cstrrchr(m_pchData, (_TUCHAR)ch); + + // return -1 if not found, distance from beginning otherwise + return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); + } + + int Find(TCHAR ch, int nStart) const // starting at index + { + int nLength = GetData()->nDataLength; + if (nStart < 0 || nStart >= nLength) + return -1; + + // find first single character + LPCTSTR lpsz = _cstrchr(m_pchData + nStart, (_TUCHAR)ch); + + // return -1 if not found and index otherwise + return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); + } + + int FindOneOf(LPCTSTR lpszCharSet) const + { + ATLASSERT(_IsValidString(lpszCharSet)); + LPCTSTR lpsz = _cstrpbrk(m_pchData, lpszCharSet); + return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); + } + + // look for a specific sub-string + // find a sub-string (like strstr) + int Find(LPCTSTR lpszSub) const // like "C" strstr + { + return Find(lpszSub, 0); + } + + int Find(LPCTSTR lpszSub, int nStart) const // starting at index + { + ATLASSERT(_IsValidString(lpszSub)); + + int nLength = GetData()->nDataLength; + if (nStart < 0 || nStart > nLength) + return -1; + + // find first matching substring + LPCTSTR lpsz = _cstrstr(m_pchData + nStart, lpszSub); + + // return -1 for not found, distance from beginning otherwise + return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); + } + + // Concatentation for non strings + CString& Append(int n) + { + const int cchBuff = 12; + TCHAR szBuffer[cchBuff] = { 0 }; + SecureHelper::wsprintf_x(szBuffer, cchBuff, _T("%d"), n); + ConcatInPlace(SafeStrlen(szBuffer), szBuffer); + return *this; + } + + // simple formatting + // formatting (using wsprintf style formatting) + BOOL __cdecl Format(LPCTSTR lpszFormat, ...) + { + ATLASSERT(_IsValidString(lpszFormat)); + + va_list argList; + va_start(argList, lpszFormat); + BOOL bRet = FormatV(lpszFormat, argList); + va_end(argList); + return bRet; + } + + BOOL __cdecl Format(UINT nFormatID, ...) + { + CString strFormat; + BOOL bRet = strFormat.LoadString(nFormatID); + ATLASSERT(bRet != 0); + + va_list argList; + va_start(argList, nFormatID); + bRet = FormatV(strFormat, argList); + va_end(argList); + return bRet; + } + + BOOL FormatV(LPCTSTR lpszFormat, va_list argList) + { + ATLASSERT(_IsValidString(lpszFormat)); + + enum _FormatModifiers + { + FORCE_ANSI = 0x10000, + FORCE_UNICODE = 0x20000, + FORCE_INT64 = 0x40000 + }; + + va_list argListSave = argList; + + // make a guess at the maximum length of the resulting string + int nMaxLen = 0; + for (LPCTSTR lpsz = lpszFormat; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz)) + { + // handle '%' character, but watch out for '%%' + if (*lpsz != _T('%') || *(lpsz = ::CharNext(lpsz)) == _T('%')) + { + nMaxLen += (int)(::CharNext(lpsz) - lpsz); + continue; + } + + int nItemLen = 0; + + // handle '%' character with format + int nWidth = 0; + for (; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz)) + { + // check for valid flags + if (*lpsz == _T('#')) + nMaxLen += 2; // for '0x' + else if (*lpsz == _T('*')) + nWidth = va_arg(argList, int); + else if (*lpsz == _T('-') || *lpsz == _T('+') || *lpsz == _T('0') || *lpsz == _T(' ')) + ; + else // hit non-flag character + break; + } + // get width and skip it + if (nWidth == 0) + { + // width indicated by + nWidth = _cstrtoi(lpsz); + for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz)) + ; + } + ATLASSERT(nWidth >= 0); + + int nPrecision = 0; + if (*lpsz == _T('.')) + { + // skip past '.' separator (width.precision) + lpsz = ::CharNext(lpsz); + + // get precision and skip it + if (*lpsz == _T('*')) + { + nPrecision = va_arg(argList, int); + lpsz = ::CharNext(lpsz); + } + else + { + nPrecision = _cstrtoi(lpsz); + for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz)) + ; + } + ATLASSERT(nPrecision >= 0); + } + + // should be on type modifier or specifier + int nModifier = 0; + if(lpsz[0] == _T('I') && lpsz[1] == _T('6') && lpsz[2] == _T('4')) + { + lpsz += 3; + nModifier = FORCE_INT64; + } + else + { + switch (*lpsz) + { + // modifiers that affect size + case _T('h'): + nModifier = FORCE_ANSI; + lpsz = ::CharNext(lpsz); + break; + case _T('l'): + nModifier = FORCE_UNICODE; + lpsz = ::CharNext(lpsz); + break; + + // modifiers that do not affect size + case _T('F'): + case _T('N'): + case _T('L'): + lpsz = ::CharNext(lpsz); + break; + } + } + + // now should be on specifier + switch (*lpsz | nModifier) + { + // single characters + case _T('c'): + case _T('C'): + nItemLen = 2; + va_arg(argList, TCHAR); + break; + case _T('c') | FORCE_ANSI: + case _T('C') | FORCE_ANSI: + nItemLen = 2; + va_arg(argList, char); + break; + case _T('c') | FORCE_UNICODE: + case _T('C') | FORCE_UNICODE: + nItemLen = 2; + va_arg(argList, WCHAR); + break; + + // strings + case _T('s'): + { + LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { + nItemLen = lstrlen(pstrNextArg); + nItemLen = max(1, nItemLen); + } + break; + } + + case _T('S'): + { +#ifndef _UNICODE + LPWSTR pstrNextArg = va_arg(argList, LPWSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { + nItemLen = (int)wcslen(pstrNextArg); + nItemLen = max(1, nItemLen); + } +#else // _UNICODE + LPCSTR pstrNextArg = va_arg(argList, LPCSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + nItemLen = ATL::lstrlenA(pstrNextArg); +#else + nItemLen = lstrlenA(pstrNextArg); +#endif + nItemLen = max(1, nItemLen); + } +#endif // _UNICODE + break; + } + + case _T('s') | FORCE_ANSI: + case _T('S') | FORCE_ANSI: + { + LPCSTR pstrNextArg = va_arg(argList, LPCSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { +#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) + nItemLen = ATL::lstrlenA(pstrNextArg); +#else + nItemLen = lstrlenA(pstrNextArg); +#endif + nItemLen = max(1, nItemLen); + } + break; + } + + case _T('s') | FORCE_UNICODE: + case _T('S') | FORCE_UNICODE: + { + LPWSTR pstrNextArg = va_arg(argList, LPWSTR); + if (pstrNextArg == NULL) + { + nItemLen = 6; // "(null)" + } + else + { + nItemLen = (int)wcslen(pstrNextArg); + nItemLen = max(1, nItemLen); + } + break; + } + } + + // adjust nItemLen for strings + if (nItemLen != 0) + { + nItemLen = max(nItemLen, nWidth); + if (nPrecision != 0) + nItemLen = min(nItemLen, nPrecision); + } + else + { + switch (*lpsz) + { + // integers + case _T('d'): + case _T('i'): + case _T('u'): + case _T('x'): + case _T('X'): + case _T('o'): + if (nModifier & FORCE_INT64) + va_arg(argList, __int64); + else + va_arg(argList, int); + nItemLen = 32; + nItemLen = max(nItemLen, nWidth + nPrecision); + break; + +#ifndef _ATL_USE_CSTRING_FLOAT + case _T('e'): + case _T('E'): + case _T('f'): + case _T('g'): + case _T('G'): + ATLASSERT(!"Floating point (%%e, %%E, %%f, %%g, and %%G) is not supported by the WTL::CString class."); +#ifndef _DEBUG + ::OutputDebugString(_T("Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class.")); +#ifndef _WIN32_WCE + ::DebugBreak(); +#else // CE specific + DebugBreak(); +#endif // _WIN32_WCE +#endif // !_DEBUG + break; +#else // _ATL_USE_CSTRING_FLOAT + case _T('e'): + case _T('E'): + case _T('g'): + case _T('G'): + va_arg(argList, double); + nItemLen = 128; + nItemLen = max(nItemLen, nWidth + nPrecision); + break; + case _T('f'): + { + double f = va_arg(argList, double); + // 312 == strlen("-1+(309 zeroes).") + // 309 zeroes == max precision of a double + // 6 == adjustment in case precision is not specified, + // which means that the precision defaults to 6 + int cchLen = max(nWidth, 312 + nPrecision + 6); + CTempBuffer buff; + LPTSTR pszTemp = buff.Allocate(cchLen); + if(pszTemp != NULL) + { + SecureHelper::sprintf_x(pszTemp, cchLen, _T("%*.*f"), nWidth, nPrecision + 6, f); + nItemLen = (int)_tcslen(pszTemp); + } + else + { + nItemLen = cchLen; + } + } + break; +#endif // _ATL_USE_CSTRING_FLOAT + + case _T('p'): + va_arg(argList, void*); + nItemLen = 32; + nItemLen = max(nItemLen, nWidth + nPrecision); + break; + + // no output + case _T('n'): + va_arg(argList, int*); + break; + + default: + ATLASSERT(FALSE); // unknown formatting option + } + } + + // adjust nMaxLen for output nItemLen + nMaxLen += nItemLen; + } + + if(GetBuffer(nMaxLen) == NULL) + return FALSE; +#ifndef _ATL_USE_CSTRING_FLOAT + int nRet = SecureHelper::wvsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave); +#else // _ATL_USE_CSTRING_FLOAT + int nRet = SecureHelper::vsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave); +#endif // _ATL_USE_CSTRING_FLOAT + nRet; // ref + ATLASSERT(nRet <= GetAllocLength()); + ReleaseBuffer(); + + va_end(argListSave); + return TRUE; + } + + // formatting for localization (uses FormatMessage API) + // formatting (using FormatMessage style formatting) + BOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...) + { + // format message into temporary buffer lpszTemp + va_list argList; + va_start(argList, lpszFormat); + LPTSTR lpszTemp; + BOOL bRet = TRUE; + + if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, + lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL) + bRet = FALSE; + + // assign lpszTemp into the resulting string and free the temporary + *this = lpszTemp; + LocalFree(lpszTemp); + va_end(argList); + return bRet; + } + + BOOL __cdecl FormatMessage(UINT nFormatID, ...) + { + // get format string from string table + CString strFormat; + BOOL bRetTmp = strFormat.LoadString(nFormatID); + bRetTmp; // ref + ATLASSERT(bRetTmp != 0); + + // format message into temporary buffer lpszTemp + va_list argList; + va_start(argList, nFormatID); + LPTSTR lpszTemp; + BOOL bRet = TRUE; + + if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, + strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL) + bRet = FALSE; + + // assign lpszTemp into the resulting string and free lpszTemp + *this = lpszTemp; + LocalFree(lpszTemp); + va_end(argList); + return bRet; + } + + // Windows support + BOOL LoadString(UINT nID) // load from string resource (255 chars max.) + { +#ifdef _UNICODE + const int CHAR_FUDGE = 1; // one TCHAR unused is good enough +#else + const int CHAR_FUDGE = 2; // two BYTES unused for case of DBC last char +#endif + + // try fixed buffer first (to avoid wasting space in the heap) + TCHAR szTemp[256]; + int nCount = sizeof(szTemp) / sizeof(szTemp[0]); + int nLen = _LoadString(nID, szTemp, nCount); + if (nCount - nLen > CHAR_FUDGE) + { + *this = szTemp; + return (nLen > 0); + } + + // try buffer size of 512, then larger size until entire string is retrieved + int nSize = 256; + do + { + nSize += 256; + LPTSTR lpstr = GetBuffer(nSize - 1); + if(lpstr == NULL) + { + nLen = 0; + break; + } + nLen = _LoadString(nID, lpstr, nSize); + } while (nSize - nLen <= CHAR_FUDGE); + ReleaseBuffer(); + + return (nLen > 0); + } + +#ifndef _UNICODE + // ANSI <-> OEM support (convert string in place) + void AnsiToOem() + { + CopyBeforeWrite(); + ::AnsiToOem(m_pchData, m_pchData); + } + + void OemToAnsi() + { + CopyBeforeWrite(); + ::OemToAnsi(m_pchData, m_pchData); + } +#endif + +#ifndef _ATL_NO_COM + // OLE BSTR support (use for OLE automation) + BSTR AllocSysString() const + { +#if defined(_UNICODE) || defined(OLE2ANSI) + BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength); +#else + int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData, + GetData()->nDataLength, NULL, NULL); + BSTR bstr = ::SysAllocStringLen(NULL, nLen); + if(bstr != NULL) + MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, bstr, nLen); +#endif + return bstr; + } + + BSTR SetSysString(BSTR* pbstr) const + { +#if defined(_UNICODE) || defined(OLE2ANSI) + ::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength); +#else + int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData, + GetData()->nDataLength, NULL, NULL); + if(::SysReAllocStringLen(pbstr, NULL, nLen)) + MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, *pbstr, nLen); +#endif + ATLASSERT(*pbstr != NULL); + return *pbstr; + } +#endif // !_ATL_NO_COM + + // Access to string implementation buffer as "C" character array + LPTSTR GetBuffer(int nMinBufLength) + { + ATLASSERT(nMinBufLength >= 0); + + if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength) + { + // we have to grow the buffer + CStringData* pOldData = GetData(); + int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it + if (nMinBufLength < nOldLen) + nMinBufLength = nOldLen; + + if(!AllocBuffer(nMinBufLength)) + return NULL; + + SecureHelper::memcpy_x(m_pchData, (nMinBufLength + 1) * sizeof(TCHAR), pOldData->data(), (nOldLen + 1) * sizeof(TCHAR)); + GetData()->nDataLength = nOldLen; + CString::Release(pOldData); + } + ATLASSERT(GetData()->nRefs <= 1); + + // return a pointer to the character storage for this string + ATLASSERT(m_pchData != NULL); + return m_pchData; + } + + void ReleaseBuffer(int nNewLength = -1) + { + CopyBeforeWrite(); // just in case GetBuffer was not called + + if (nNewLength == -1) + nNewLength = lstrlen(m_pchData); // zero terminated + + ATLASSERT(nNewLength <= GetData()->nAllocLength); + GetData()->nDataLength = nNewLength; + m_pchData[nNewLength] = _T('\0'); + } + + LPTSTR GetBufferSetLength(int nNewLength) + { + ATLASSERT(nNewLength >= 0); + + if(GetBuffer(nNewLength) == NULL) + return NULL; + + GetData()->nDataLength = nNewLength; + m_pchData[nNewLength] = _T('\0'); + return m_pchData; + } + + void FreeExtra() + { + ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength); + if (GetData()->nDataLength != GetData()->nAllocLength) + { + CStringData* pOldData = GetData(); + if(AllocBuffer(GetData()->nDataLength)) + { + SecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pOldData->data(), pOldData->nDataLength * sizeof(TCHAR)); + ATLASSERT(m_pchData[GetData()->nDataLength] == _T('\0')); + CString::Release(pOldData); + } + } + ATLASSERT(GetData() != NULL); + } + + // Use LockBuffer/UnlockBuffer to turn refcounting off + LPTSTR LockBuffer() + { + LPTSTR lpsz = GetBuffer(0); + if(lpsz != NULL) + GetData()->nRefs = -1; + return lpsz; + } + + void UnlockBuffer() + { + ATLASSERT(GetData()->nRefs == -1); + if (GetData() != _atltmpDataNil) + GetData()->nRefs = 1; + } + +// Implementation +public: + ~CString() // free any attached data + { + if (GetData() != _atltmpDataNil) + { + if (InterlockedDecrement(&GetData()->nRefs) <= 0) + delete[] (BYTE*)GetData(); + } + } + + int GetAllocLength() const + { + return GetData()->nAllocLength; + } + + static BOOL __stdcall _IsValidString(LPCTSTR lpsz, int /*nLength*/ = -1) + { + return (lpsz != NULL) ? TRUE : FALSE; + } + +protected: + LPTSTR m_pchData; // pointer to ref counted string data + + // implementation helpers + CStringData* GetData() const + { + ATLASSERT(m_pchData != NULL); + return ((CStringData*)m_pchData) - 1; + } + + void Init() + { + m_pchData = _GetEmptyString().m_pchData; + } + + BOOL AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const + { + // will clone the data attached to this string + // allocating 'nExtraLen' characters + // Places results in uninitialized string 'dest' + // Will copy the part or all of original data to start of new string + + BOOL bRet = FALSE; + int nNewLen = nCopyLen + nExtraLen; + if (nNewLen == 0) + { + dest.Init(); + bRet = TRUE; + } + else if(nNewLen >= nCopyLen) + { + if(dest.AllocBuffer(nNewLen)) + { + SecureHelper::memcpy_x(dest.m_pchData, (nNewLen + 1) * sizeof(TCHAR), m_pchData + nCopyIndex, nCopyLen * sizeof(TCHAR)); + bRet = TRUE; + } + } + + return bRet; + } + + // always allocate one extra character for '\0' termination + // assumes [optimistically] that data length will equal allocation length + BOOL AllocBuffer(int nLen) + { + ATLASSERT(nLen >= 0); + ATLASSERT(nLen <= INT_MAX - 1); // max size (enough room for 1 extra) + + if (nLen == 0) + { + Init(); + } + else + { + CStringData* pData = NULL; + ATLTRY(pData = (CStringData*)new BYTE[sizeof(CStringData) + (nLen + 1) * sizeof(TCHAR)]); + if(pData == NULL) + return FALSE; + + pData->nRefs = 1; + pData->data()[nLen] = _T('\0'); + pData->nDataLength = nLen; + pData->nAllocLength = nLen; + m_pchData = pData->data(); + } + + return TRUE; + } + + // Assignment operators + // All assign a new value to the string + // (a) first see if the buffer is big enough + // (b) if enough room, copy on top of old buffer, set size and type + // (c) otherwise free old string data, and create a new one + // + // All routines return the new string (but as a 'const CString&' so that + // assigning it again will cause a copy, eg: s1 = s2 = "hi there". + // + void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData) + { + if(AllocBeforeWrite(nSrcLen)) + { + SecureHelper::memcpy_x(m_pchData, (nSrcLen + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR)); + GetData()->nDataLength = nSrcLen; + m_pchData[nSrcLen] = _T('\0'); + } + } + + // Concatenation + // NOTE: "operator +" is done as friend functions for simplicity + // There are three variants: + // CString + CString + // and for ? = TCHAR, LPCTSTR + // CString + ? + // ? + CString + BOOL ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data) + { + // -- master concatenation routine + // Concatenate two sources + // -- assume that 'this' is a new CString object + + BOOL bRet = TRUE; + int nNewLen = nSrc1Len + nSrc2Len; + if(nNewLen < nSrc1Len || nNewLen < nSrc2Len) + { + bRet = FALSE; + } + else if(nNewLen != 0) + { + bRet = AllocBuffer(nNewLen); + if (bRet) + { + SecureHelper::memcpy_x(m_pchData, (nNewLen + 1) * sizeof(TCHAR), lpszSrc1Data, nSrc1Len * sizeof(TCHAR)); + SecureHelper::memcpy_x(m_pchData + nSrc1Len, (nNewLen + 1 - nSrc1Len) * sizeof(TCHAR), lpszSrc2Data, nSrc2Len * sizeof(TCHAR)); + } + } + return bRet; + } + + void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData) + { + // -- the main routine for += operators + + // concatenating an empty string is a no-op! + if (nSrcLen == 0) + return; + + // if the buffer is too small, or we have a width mis-match, just + // allocate a new buffer (slow but sure) + if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength) + { + // we have to grow the buffer, use the ConcatCopy routine + CStringData* pOldData = GetData(); + if (ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData)) + { + ATLASSERT(pOldData != NULL); + CString::Release(pOldData); + } + } + else + { + // fast concatenation when buffer big enough + SecureHelper::memcpy_x(m_pchData + GetData()->nDataLength, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR)); + GetData()->nDataLength += nSrcLen; + ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength); + m_pchData[GetData()->nDataLength] = _T('\0'); + } + } + + void CopyBeforeWrite() + { + if (GetData()->nRefs > 1) + { + CStringData* pData = GetData(); + Release(); + if(AllocBuffer(pData->nDataLength)) + SecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pData->data(), (pData->nDataLength + 1) * sizeof(TCHAR)); + } + ATLASSERT(GetData()->nRefs <= 1); + } + + BOOL AllocBeforeWrite(int nLen) + { + BOOL bRet = TRUE; + if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength) + { + Release(); + bRet = AllocBuffer(nLen); + } + ATLASSERT(GetData()->nRefs <= 1); + return bRet; + } + + void Release() + { + if (GetData() != _atltmpDataNil) + { + ATLASSERT(GetData()->nRefs != 0); + if (InterlockedDecrement(&GetData()->nRefs) <= 0) + delete[] (BYTE*)GetData(); + Init(); + } + } + + static void PASCAL Release(CStringData* pData) + { + if (pData != _atltmpDataNil) + { + ATLASSERT(pData->nRefs != 0); + if (InterlockedDecrement(&pData->nRefs) <= 0) + delete[] (BYTE*)pData; + } + } + + static int PASCAL SafeStrlen(LPCTSTR lpsz) + { + return (lpsz == NULL) ? 0 : lstrlen(lpsz); + } + + static int __stdcall _LoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf) + { +#ifdef _DEBUG + // LoadString without annoying warning from the Debug kernel if the + // segment containing the string is not present + if (::FindResource(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE((nID >> 4) + 1), RT_STRING) == NULL) + { + lpszBuf[0] = _T('\0'); + return 0; // not found + } +#endif // _DEBUG + + int nLen = ::LoadString(ModuleHelper::GetResourceInstance(), nID, lpszBuf, nMaxBuf); + if (nLen == 0) + lpszBuf[0] = _T('\0'); + + return nLen; + } + + static const CString& __stdcall _GetEmptyString() + { + return *(CString*)&_atltmpPchNil; + } + +// CString conversion helpers + static int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count) + { + if (count == 0 && mbstr != NULL) + return 0; + + int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1, mbstr, (int)count, NULL, NULL); + ATLASSERT(mbstr == NULL || result <= (int)count); + if (result > 0) + mbstr[result - 1] = 0; + return result; + } + + static int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count) + { + if (count == 0 && wcstr != NULL) + return 0; + + int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1, wcstr, (int)count); + ATLASSERT(wcstr == NULL || result <= (int)count); + if (result > 0) + wcstr[result - 1] = 0; + return result; + } + +// Helpers to avoid CRT startup code +#ifdef _ATL_MIN_CRT + static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch) + { + // strchr for '\0' should succeed + while (*p != 0) + { + if (*p == ch) + break; + p = ::CharNext(p); + } + return (*p == ch) ? p : NULL; + } + + static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch) + { + const TCHAR* lpsz = NULL; + while (*p != 0) + { + if (*p == ch) + lpsz = p; + p = ::CharNext(p); + } + return lpsz; + } + + static TCHAR* _cstrrev(TCHAR* pStr) + { + // optimize NULL, zero-length, and single-char case + if ((pStr == NULL) || (pStr[0] == _T('\0')) || (pStr[1] == _T('\0'))) + return pStr; + + TCHAR* p = pStr; + + while (*p != 0) + { + TCHAR* pNext = ::CharNext(p); + if(pNext > p + 1) + { + char p1 = *(char*)p; + *(char*)p = *(char*)(p + 1); + *(char*)(p + 1) = p1; + } + p = pNext; + } + + p--; + TCHAR* q = pStr; + + while (q < p) + { + TCHAR t = *q; + *q = *p; + *p = t; + q++; + p--; + } + return pStr; + } + + static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet) + { + int nLen = lstrlen(pCharSet); + if (nLen == 0) + return (TCHAR*)pStr; + + const TCHAR* pRet = NULL; + const TCHAR* pCur = pStr; + while((pCur = _cstrchr(pCur, *pCharSet)) != NULL) + { + if(memcmp(pCur, pCharSet, nLen * sizeof(TCHAR)) == 0) + { + pRet = pCur; + break; + } + pCur = ::CharNext(pCur); + } + return pRet; + } + + static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet) + { + int nRet = 0; + const TCHAR* p = pStr; + while (*p != 0) + { + const TCHAR* pNext = ::CharNext(p); + if(pNext > p + 1) + { + if(_cstrchr_db(pCharSet, *p, *(p + 1)) == NULL) + break; + nRet += 2; + } + else + { + if(_cstrchr(pCharSet, *p) == NULL) + break; + nRet++; + } + p = pNext; + } + return nRet; + } + + static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet) + { + int nRet = 0; + TCHAR* p = (TCHAR*)pStr; + while (*p != 0) + { + TCHAR* pNext = ::CharNext(p); + if(pNext > p + 1) + { + if(_cstrchr_db(pCharSet, *p, *(p + 1)) != NULL) + break; + nRet += 2; + } + else + { + if(_cstrchr(pCharSet, *p) != NULL) + break; + nRet++; + } + p = pNext; + } + return nRet; + } + + static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet) + { + int n = _cstrcspn(p, lpszCharSet); + return (p[n] != 0) ? &p[n] : NULL; + } + + static int _cstrisdigit(TCHAR ch) + { + WORD type; + GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type); + return (type & C1_DIGIT) == C1_DIGIT; + } + + static int _cstrisspace(TCHAR ch) + { + WORD type; + GetStringTypeEx(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type); + return (type & C1_SPACE) == C1_SPACE; + } + + static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return lstrcmp(pstrOne, pstrOther); + } + + static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return lstrcmpi(pstrOne, pstrOther); + } + + static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + int nRet = CompareString(GetThreadLocale(), 0, pstrOne, -1, pstrOther, -1); + ATLASSERT(nRet != 0); + return nRet - 2; // convert to strcmp convention + } + + static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + int nRet = CompareString(GetThreadLocale(), NORM_IGNORECASE, pstrOne, -1, pstrOther, -1); + ATLASSERT(nRet != 0); + return nRet - 2; // convert to strcmp convention + } + + static int _cstrtoi(const TCHAR* nptr) + { + int c; // current char + int total; // current total + int sign; // if '-', then negative, otherwise positive + + while (_cstrisspace(*nptr)) + ++nptr; + + c = (int)(_TUCHAR)*nptr++; + sign = c; // save sign indication + if (c == _T('-') || c == _T('+')) + c = (int)(_TUCHAR)*nptr++; // skip sign + + total = 0; + + while (_cstrisdigit((TCHAR)c)) + { + total = 10 * total + (c - '0'); // accumulate digit + c = (int)(_TUCHAR)*nptr++; // get next char + } + + if (sign == '-') + return -total; + else + return total; // return result, negated if necessary + } +#else // !_ATL_MIN_CRT + static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch) + { + return _tcschr(p, ch); + } + + static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch) + { + return _tcsrchr(p, ch); + } + + static TCHAR* _cstrrev(TCHAR* pStr) + { + return _tcsrev(pStr); + } + + static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet) + { + return _tcsstr(pStr, pCharSet); + } + + static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet) + { + return (int)_tcsspn(pStr, pCharSet); + } + + static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet) + { + return (int)_tcscspn(pStr, pCharSet); + } + + static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet) + { + return _tcspbrk(p, lpszCharSet); + } + + static int _cstrisdigit(TCHAR ch) + { + return _istdigit(ch); + } + + static int _cstrisspace(TCHAR ch) + { + return _istspace((_TUCHAR)ch); + } + + static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return _tcscmp(pstrOne, pstrOther); + } + + static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return _tcsicmp(pstrOne, pstrOther); + } + +#ifndef _WIN32_WCE + static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return _tcscoll(pstrOne, pstrOther); + } + + static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther) + { + return _tcsicoll(pstrOne, pstrOther); + } +#endif // !_WIN32_WCE + + static int _cstrtoi(const TCHAR* nptr) + { + return _ttoi(nptr); + } +#endif // !_ATL_MIN_CRT + + static const TCHAR* _cstrchr_db(const TCHAR* p, TCHAR ch1, TCHAR ch2) + { + const TCHAR* lpsz = NULL; + while (*p != 0) + { + if (*p == ch1 && *(p + 1) == ch2) + { + lpsz = p; + break; + } + p = ::CharNext(p); + } + return lpsz; + } +}; + + +// Compare helpers + +inline bool __stdcall operator ==(const CString& s1, const CString& s2) +{ return s1.Compare(s2) == 0; } + +inline bool __stdcall operator ==(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) == 0; } + +inline bool __stdcall operator ==(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) == 0; } + +inline bool __stdcall operator !=(const CString& s1, const CString& s2) +{ return s1.Compare(s2) != 0; } + +inline bool __stdcall operator !=(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) != 0; } + +inline bool __stdcall operator !=(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) != 0; } + +inline bool __stdcall operator <(const CString& s1, const CString& s2) +{ return s1.Compare(s2) < 0; } + +inline bool __stdcall operator <(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) < 0; } + +inline bool __stdcall operator <(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) > 0; } + +inline bool __stdcall operator >(const CString& s1, const CString& s2) +{ return s1.Compare(s2) > 0; } + +inline bool __stdcall operator >(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) > 0; } + +inline bool __stdcall operator >(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) < 0; } + +inline bool __stdcall operator <=(const CString& s1, const CString& s2) +{ return s1.Compare(s2) <= 0; } + +inline bool __stdcall operator <=(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) <= 0; } + +inline bool __stdcall operator <=(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) >= 0; } + +inline bool __stdcall operator >=(const CString& s1, const CString& s2) +{ return s1.Compare(s2) >= 0; } + +inline bool __stdcall operator >=(const CString& s1, LPCTSTR s2) +{ return s1.Compare(s2) >= 0; } + +inline bool __stdcall operator >=(LPCTSTR s1, const CString& s2) +{ return s2.Compare(s1) <= 0; } + + +// CString "operator +" functions + +inline CString __stdcall operator +(const CString& string1, const CString& string2) +{ + CString s; + s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, string2.GetData()->nDataLength, string2.m_pchData); + return s; +} + +inline CString __stdcall operator +(const CString& string, TCHAR ch) +{ + CString s; + s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, 1, &ch); + return s; +} + +inline CString __stdcall operator +(TCHAR ch, const CString& string) +{ + CString s; + s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData); + return s; +} + +#ifdef _UNICODE +inline CString __stdcall operator +(const CString& string, char ch) +{ + return string + (TCHAR)ch; +} + +inline CString __stdcall operator +(char ch, const CString& string) +{ + return (TCHAR)ch + string; +} +#endif // _UNICODE + +inline CString __stdcall operator +(const CString& string, LPCTSTR lpsz) +{ + ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz)); + CString s; + s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, CString::SafeStrlen(lpsz), lpsz); + return s; +} + +inline CString __stdcall operator +(LPCTSTR lpsz, const CString& string) +{ + ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz)); + CString s; + s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength, string.m_pchData); + return s; +} + +#endif // !_WTL_NO_CSTRING + + +/////////////////////////////////////////////////////////////////////////////// +// CRecentDocumentList - MRU List Support + +#ifndef _WIN32_WCE + +#ifndef _WTL_MRUEMPTY_TEXT + #define _WTL_MRUEMPTY_TEXT _T("(empty)") +#endif + +// forward declaration +inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen); + +template +class CRecentDocumentListBase +{ +public: +// Declarations + struct _DocEntry + { + TCHAR szDocName[t_cchItemLen]; + bool operator ==(const _DocEntry& de) const + { return (lstrcmpi(szDocName, de.szDocName) == 0); } + }; + + enum + { + m_nMaxEntries_Min = 2, + m_nMaxEntries_Max = t_nLastID - t_nFirstID + 1, + m_cchMaxItemLen_Min = 6, + m_cchMaxItemLen_Max = t_cchItemLen, + m_cchItemNameLen = 11 + }; + +// Data members + ATL::CSimpleArray<_DocEntry> m_arrDocs; + int m_nMaxEntries; // default is 4 + HMENU m_hMenu; + + TCHAR m_szNoEntries[t_cchItemLen]; + + int m_cchMaxItemLen; + +// Constructor + CRecentDocumentListBase() : m_hMenu(NULL), m_nMaxEntries(4), m_cchMaxItemLen(-1) + { + // These ASSERTs verify values of the template arguments + ATLASSERT(t_cchItemLen > m_cchMaxItemLen_Min); + ATLASSERT(m_nMaxEntries_Max > m_nMaxEntries_Min); + } + +// Attributes + HMENU GetMenuHandle() const + { + return m_hMenu; + } + + void SetMenuHandle(HMENU hMenu) + { + ATLASSERT(hMenu == NULL || ::IsMenu(hMenu)); + m_hMenu = hMenu; + if(m_hMenu == NULL || (::GetMenuString(m_hMenu, t_nFirstID, m_szNoEntries, t_cchItemLen, MF_BYCOMMAND) == 0)) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + SecureHelper::strncpy_x(m_szNoEntries, _countof(m_szNoEntries), pT->GetMRUEmptyText(), _TRUNCATE); + } + } + + int GetMaxEntries() const + { + return m_nMaxEntries; + } + + void SetMaxEntries(int nMaxEntries) + { + ATLASSERT(nMaxEntries >= m_nMaxEntries_Min && nMaxEntries <= m_nMaxEntries_Max); + if(nMaxEntries < m_nMaxEntries_Min) + nMaxEntries = m_nMaxEntries_Min; + else if(nMaxEntries > m_nMaxEntries_Max) + nMaxEntries = m_nMaxEntries_Max; + m_nMaxEntries = nMaxEntries; + } + + int GetMaxItemLength() const + { + return m_cchMaxItemLen; + } + + void SetMaxItemLength(int cchMaxLen) + { + ATLASSERT((cchMaxLen >= m_cchMaxItemLen_Min && cchMaxLen <= m_cchMaxItemLen_Max) || cchMaxLen == -1); + if(cchMaxLen != -1) + { + if(cchMaxLen < m_cchMaxItemLen_Min) + cchMaxLen = m_cchMaxItemLen_Min; + else if(cchMaxLen > m_cchMaxItemLen_Max) + cchMaxLen = m_cchMaxItemLen_Max; + } + m_cchMaxItemLen = cchMaxLen; + T* pT = static_cast(this); + pT->UpdateMenu(); + } + +// Operations + BOOL AddToList(LPCTSTR lpstrDocName) + { + _DocEntry de; + errno_t nRet = SecureHelper::strncpy_x(de.szDocName, _countof(de.szDocName), lpstrDocName, _TRUNCATE); + if(nRet != 0 && nRet != STRUNCATE) + return FALSE; + + for(int i = 0; i < m_arrDocs.GetSize(); i++) + { + if(lstrcmpi(m_arrDocs[i].szDocName, lpstrDocName) == 0) + { + m_arrDocs.RemoveAt(i); + break; + } + } + + if(m_arrDocs.GetSize() == m_nMaxEntries) + m_arrDocs.RemoveAt(0); + + BOOL bRet = m_arrDocs.Add(de); + if(bRet) + { + T* pT = static_cast(this); + bRet = pT->UpdateMenu(); + } + return bRet; + } + + // This function is deprecated because it is not safe. + // Use the version below that accepts the buffer length. +#if (_MSC_VER >= 1300) + __declspec(deprecated) +#endif + BOOL GetFromList(int /*nItemID*/, LPTSTR /*lpstrDocName*/) + { + ATLASSERT(FALSE); + return FALSE; + } + + BOOL GetFromList(int nItemID, LPTSTR lpstrDocName, int cchLength) + { + int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; + if(nIndex < 0 || nIndex >= m_arrDocs.GetSize()) + return FALSE; + if(lstrlen(m_arrDocs[nIndex].szDocName) >= cchLength) + return FALSE; + SecureHelper::strcpy_x(lpstrDocName, cchLength, m_arrDocs[nIndex].szDocName); + + return TRUE; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + BOOL GetFromList(int nItemID, _CSTRING_NS::CString& strDocName) + { + int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; + if(nIndex < 0 || nIndex >= m_arrDocs.GetSize()) + return FALSE; + strDocName = m_arrDocs[nIndex].szDocName; + return TRUE; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL RemoveFromList(int nItemID) + { + int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; + BOOL bRet = m_arrDocs.RemoveAt(nIndex); + if(bRet) + { + T* pT = static_cast(this); + bRet = pT->UpdateMenu(); + } + return bRet; + } + + BOOL MoveToTop(int nItemID) + { + int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; + if(nIndex < 0 || nIndex >= m_arrDocs.GetSize()) + return FALSE; + _DocEntry de; + de = m_arrDocs[nIndex]; + m_arrDocs.RemoveAt(nIndex); + BOOL bRet = m_arrDocs.Add(de); + if(bRet) + { + T* pT = static_cast(this); + bRet = pT->UpdateMenu(); + } + return bRet; + } + + BOOL ReadFromRegistry(LPCTSTR lpstrRegKey) + { + T* pT = static_cast(this); + ATL::CRegKey rkParent; + ATL::CRegKey rk; + + LONG lRet = rkParent.Open(HKEY_CURRENT_USER, lpstrRegKey); + if(lRet != ERROR_SUCCESS) + return FALSE; + lRet = rk.Open(rkParent, pT->GetRegKeyName()); + if(lRet != ERROR_SUCCESS) + return FALSE; + + DWORD dwRet = 0; +#if (_ATL_VER >= 0x0700) + lRet = rk.QueryDWORDValue(pT->GetRegCountName(), dwRet); +#else + lRet = rk.QueryValue(dwRet, pT->GetRegCountName()); +#endif + if(lRet != ERROR_SUCCESS) + return FALSE; + SetMaxEntries(dwRet); + + m_arrDocs.RemoveAll(); + + TCHAR szRetString[t_cchItemLen] = { 0 }; + _DocEntry de; + + for(int nItem = m_nMaxEntries; nItem > 0; nItem--) + { + TCHAR szBuff[m_cchItemNameLen] = { 0 }; + SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem); +#if (_ATL_VER >= 0x0700) + ULONG ulCount = t_cchItemLen; + lRet = rk.QueryStringValue(szBuff, szRetString, &ulCount); +#else + DWORD dwCount = t_cchItemLen * sizeof(TCHAR); + lRet = rk.QueryValue(szRetString, szBuff, &dwCount); +#endif + if(lRet == ERROR_SUCCESS) + { + SecureHelper::strcpy_x(de.szDocName, _countof(de.szDocName), szRetString); + m_arrDocs.Add(de); + } + } + + rk.Close(); + rkParent.Close(); + + return pT->UpdateMenu(); + } + + BOOL WriteToRegistry(LPCTSTR lpstrRegKey) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + ATL::CRegKey rkParent; + ATL::CRegKey rk; + + LONG lRet = rkParent.Create(HKEY_CURRENT_USER, lpstrRegKey); + if(lRet != ERROR_SUCCESS) + return FALSE; + lRet = rk.Create(rkParent, pT->GetRegKeyName()); + if(lRet != ERROR_SUCCESS) + return FALSE; + +#if (_ATL_VER >= 0x0700) + lRet = rk.SetDWORDValue(pT->GetRegCountName(), m_nMaxEntries); +#else + lRet = rk.SetValue(m_nMaxEntries, pT->GetRegCountName()); +#endif + ATLASSERT(lRet == ERROR_SUCCESS); + + // set new values + int nItem; + for(nItem = m_arrDocs.GetSize(); nItem > 0; nItem--) + { + TCHAR szBuff[m_cchItemNameLen] = { 0 }; + SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem); + TCHAR szDocName[t_cchItemLen] = { 0 }; + GetFromList(t_nFirstID + nItem - 1, szDocName, t_cchItemLen); +#if (_ATL_VER >= 0x0700) + lRet = rk.SetStringValue(szBuff, szDocName); +#else + lRet = rk.SetValue(szDocName, szBuff); +#endif + ATLASSERT(lRet == ERROR_SUCCESS); + } + + // delete unused keys + for(nItem = m_arrDocs.GetSize() + 1; nItem < m_nMaxEntries_Max; nItem++) + { + TCHAR szBuff[m_cchItemNameLen] = { 0 }; + SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem); + rk.DeleteValue(szBuff); + } + + rk.Close(); + rkParent.Close(); + + return TRUE; + } + +// Implementation + BOOL UpdateMenu() + { + if(m_hMenu == NULL) + return FALSE; + ATLASSERT(::IsMenu(m_hMenu)); + + int nItems = ::GetMenuItemCount(m_hMenu); + int nInsertPoint; + for(nInsertPoint = 0; nInsertPoint < nItems; nInsertPoint++) + { + CMenuItemInfo mi; + mi.fMask = MIIM_ID; + ::GetMenuItemInfo(m_hMenu, nInsertPoint, TRUE, &mi); + if (mi.wID == t_nFirstID) + break; + } + ATLASSERT(nInsertPoint < nItems && "You need a menu item with an ID = t_nFirstID"); + + int nItem; + for(nItem = t_nFirstID; nItem < t_nFirstID + m_nMaxEntries; nItem++) + { + // keep the first one as an insertion point + if (nItem != t_nFirstID) + ::DeleteMenu(m_hMenu, nItem, MF_BYCOMMAND); + } + + TCHAR szItemText[t_cchItemLen + 6] = { 0 }; // add space for &, 2 digits, and a space + int nSize = m_arrDocs.GetSize(); + nItem = 0; + if(nSize > 0) + { + for(nItem = 0; nItem < nSize; nItem++) + { + if(m_cchMaxItemLen == -1) + { + SecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, m_arrDocs[nSize - 1 - nItem].szDocName); + } + else + { + TCHAR szBuff[t_cchItemLen] = { 0 }; + T* pT = static_cast(this); + pT; // avoid level 4 warning + bool bRet = pT->CompactDocumentName(szBuff, m_arrDocs[nSize - 1 - nItem].szDocName, m_cchMaxItemLen); + bRet; // avoid level 4 warning + ATLASSERT(bRet); + SecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, szBuff); + } + ::InsertMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION | MF_STRING, t_nFirstID + nItem, szItemText); + } + } + else // empty + { + ::InsertMenu(m_hMenu, nInsertPoint, MF_BYPOSITION | MF_STRING, t_nFirstID, m_szNoEntries); + ::EnableMenuItem(m_hMenu, t_nFirstID, MF_GRAYED); + nItem++; + } + ::DeleteMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION); + + return TRUE; + } + +// Overrideables + // override to provide a different method of compacting document names + static bool CompactDocumentName(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen) + { + return AtlCompactPath(lpstrOut, lpstrIn, cchLen); + } + + static LPCTSTR GetRegKeyName() + { + return _T("Recent Document List"); + } + + static LPCTSTR GetRegCountName() + { + return _T("DocumentCount"); + } + + static LPCTSTR GetRegItemName() + { + // Note: This string is a format string used with wsprintf(). + // Resulting formatted string must be m_cchItemNameLen or less + // characters long, including the terminating null character. + return _T("Document%i"); + } + + static LPCTSTR GetMRUEmptyText() + { + return _WTL_MRUEMPTY_TEXT; + } +}; + +class CRecentDocumentList : public CRecentDocumentListBase +{ +public: +// nothing here +}; + +#endif // _WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CFindFile - file search helper class + +class CFindFile +{ +public: +// Data members + WIN32_FIND_DATA m_fd; + TCHAR m_lpszRoot[MAX_PATH]; + TCHAR m_chDirSeparator; + HANDLE m_hFind; + BOOL m_bFound; + +// Constructor/destructor + CFindFile() : m_hFind(NULL), m_chDirSeparator(_T('\\')), m_bFound(FALSE) + { } + + ~CFindFile() + { + Close(); + } + +// Attributes + ULONGLONG GetFileSize() const + { + ATLASSERT(m_hFind != NULL); + + ULARGE_INTEGER nFileSize = { 0 }; + + if(m_bFound) + { + nFileSize.LowPart = m_fd.nFileSizeLow; + nFileSize.HighPart = m_fd.nFileSizeHigh; + } + else + { + nFileSize.QuadPart = 0; + } + + return nFileSize.QuadPart; + } + + BOOL GetFileName(LPTSTR lpstrFileName, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + if(lstrlen(m_fd.cFileName) >= cchLength) + return FALSE; + + if(m_bFound) + SecureHelper::strcpy_x(lpstrFileName, cchLength, m_fd.cFileName); + + return m_bFound; + } + + BOOL GetFilePath(LPTSTR lpstrFilePath, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + + int nLen = lstrlen(m_lpszRoot); +#ifndef _WIN32_WCE + ATLASSERT(nLen > 0); + if(nLen == 0) + return FALSE; + + bool bAddSep = (m_lpszRoot[nLen - 1] != _T('\\') && m_lpszRoot[nLen - 1] !=_T('/')); +#else // CE specific + // allow diskless devices (nLen == 0) + bool bAddSep = ((nLen == 0) || (m_lpszRoot[nLen - 1] != _T('\\') && m_lpszRoot[nLen - 1] !=_T('/'))); +#endif // _WIN32_WCE + + if((lstrlen(m_lpszRoot) + (bAddSep ? 1 : 0)) >= cchLength) + return FALSE; + + SecureHelper::strcpy_x(lpstrFilePath, cchLength, m_lpszRoot); + + if(bAddSep) + { + TCHAR szSeparator[2] = { m_chDirSeparator, 0 }; + SecureHelper::strcat_x(lpstrFilePath, cchLength, szSeparator); + } + + SecureHelper::strcat_x(lpstrFilePath, cchLength, m_fd.cFileName); + + return TRUE; + } + +#ifndef _WIN32_WCE + BOOL GetFileTitle(LPTSTR lpstrFileTitle, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + + TCHAR szBuff[MAX_PATH] = { 0 }; + if(!GetFileName(szBuff, MAX_PATH)) + return FALSE; + + if(lstrlen(szBuff) >= cchLength || cchLength < 1) + return FALSE; + + // find the last dot + LPTSTR pstrDot = (LPTSTR)_cstrrchr(szBuff, _T('.')); + if(pstrDot != NULL) + *pstrDot = 0; + + SecureHelper::strcpy_x(lpstrFileTitle, cchLength, szBuff); + + return TRUE; + } +#endif // !_WIN32_WCE + + BOOL GetFileURL(LPTSTR lpstrFileURL, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + + TCHAR szBuff[MAX_PATH] = { 0 }; + if(!GetFilePath(szBuff, MAX_PATH)) + return FALSE; + LPCTSTR lpstrFileURLPrefix = _T("file://"); + if(lstrlen(szBuff) + lstrlen(lpstrFileURLPrefix) >= cchLength) + return FALSE; + SecureHelper::strcpy_x(lpstrFileURL, cchLength, lpstrFileURLPrefix); + SecureHelper::strcat_x(lpstrFileURL, cchLength, szBuff); + + return TRUE; + } + + BOOL GetRoot(LPTSTR lpstrRoot, int cchLength) const + { + ATLASSERT(m_hFind != NULL); + if(lstrlen(m_lpszRoot) >= cchLength) + return FALSE; + + SecureHelper::strcpy_x(lpstrRoot, cchLength, m_lpszRoot); + + return TRUE; + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + _CSTRING_NS::CString GetFileName() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString ret; + + if(m_bFound) + ret = m_fd.cFileName; + return ret; + } + + _CSTRING_NS::CString GetFilePath() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString strResult = m_lpszRoot; + int nLen = strResult.GetLength(); +#ifndef _WIN32_WCE + ATLASSERT(nLen > 0); + if(nLen == 0) + return strResult; + + if((strResult[nLen - 1] != _T('\\')) && (strResult[nLen - 1] != _T('/'))) +#else // CE specific + // allow diskless devices (nLen == 0) + if((nLen == 0) || ((strResult[nLen - 1] != _T('\\')) && (strResult[nLen - 1] != _T('/')))) +#endif // _WIN32_WCE + strResult += m_chDirSeparator; + strResult += GetFileName(); + return strResult; + } + +#ifndef _WIN32_WCE + _CSTRING_NS::CString GetFileTitle() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString strResult; + GetFileTitle(strResult.GetBuffer(MAX_PATH), MAX_PATH); + strResult.ReleaseBuffer(); + + return strResult; + } +#endif // !_WIN32_WCE + + _CSTRING_NS::CString GetFileURL() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString strResult("file://"); + strResult += GetFilePath(); + return strResult; + } + + _CSTRING_NS::CString GetRoot() const + { + ATLASSERT(m_hFind != NULL); + + _CSTRING_NS::CString str = m_lpszRoot; + return str; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + BOOL GetLastWriteTime(FILETIME* pTimeStamp) const + { + ATLASSERT(m_hFind != NULL); + ATLASSERT(pTimeStamp != NULL); + + if(m_bFound && pTimeStamp != NULL) + { + *pTimeStamp = m_fd.ftLastWriteTime; + return TRUE; + } + + return FALSE; + } + + BOOL GetLastAccessTime(FILETIME* pTimeStamp) const + { + ATLASSERT(m_hFind != NULL); + ATLASSERT(pTimeStamp != NULL); + + if(m_bFound && pTimeStamp != NULL) + { + *pTimeStamp = m_fd.ftLastAccessTime; + return TRUE; + } + + return FALSE; + } + + BOOL GetCreationTime(FILETIME* pTimeStamp) const + { + ATLASSERT(m_hFind != NULL); + + if(m_bFound && pTimeStamp != NULL) + { + *pTimeStamp = m_fd.ftCreationTime; + return TRUE; + } + + return FALSE; + } + + BOOL MatchesMask(DWORD dwMask) const + { + ATLASSERT(m_hFind != NULL); + + if(m_bFound) + return ((m_fd.dwFileAttributes & dwMask) != 0); + + return FALSE; + } + + BOOL IsDots() const + { + ATLASSERT(m_hFind != NULL); + + // return TRUE if the file name is "." or ".." and + // the file is a directory + + BOOL bResult = FALSE; + if(m_bFound && IsDirectory()) + { + if(m_fd.cFileName[0] == _T('.') && (m_fd.cFileName[1] == _T('\0') || (m_fd.cFileName[1] == _T('.') && m_fd.cFileName[2] == _T('\0')))) + bResult = TRUE; + } + + return bResult; + } + + BOOL IsReadOnly() const + { + return MatchesMask(FILE_ATTRIBUTE_READONLY); + } + + BOOL IsDirectory() const + { + return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); + } + + BOOL IsCompressed() const + { + return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); + } + + BOOL IsSystem() const + { + return MatchesMask(FILE_ATTRIBUTE_SYSTEM); + } + + BOOL IsHidden() const + { + return MatchesMask(FILE_ATTRIBUTE_HIDDEN); + } + + BOOL IsTemporary() const + { + return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); + } + + BOOL IsNormal() const + { + return MatchesMask(FILE_ATTRIBUTE_NORMAL); + } + + BOOL IsArchived() const + { + return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); + } + +// Operations + BOOL FindFile(LPCTSTR pstrName = NULL) + { + Close(); + + if(pstrName == NULL) + { + pstrName = _T("*.*"); + } + else if(lstrlen(pstrName) >= MAX_PATH) + { + ATLASSERT(FALSE); + return FALSE; + } + + SecureHelper::strcpy_x(m_fd.cFileName, _countof(m_fd.cFileName), pstrName); + + m_hFind = ::FindFirstFile(pstrName, &m_fd); + + if(m_hFind == INVALID_HANDLE_VALUE) + return FALSE; + +#ifndef _WIN32_WCE + bool bFullPath = (::GetFullPathName(pstrName, MAX_PATH, m_lpszRoot, NULL) != 0); +#else // CE specific + errno_t nRet = SecureHelper::strncpy_x(m_lpszRoot, _countof(m_lpszRoot), pstrName, _TRUNCATE); + bool bFullPath = (nRet == 0 || nRet == STRUNCATE); +#endif // _WIN32_WCE + + // passed name isn't a valid path but was found by the API + ATLASSERT(bFullPath); + if(!bFullPath) + { + Close(); + ::SetLastError(ERROR_INVALID_NAME); + return FALSE; + } + else + { + // find the last forward or backward whack + LPTSTR pstrBack = (LPTSTR)_cstrrchr(m_lpszRoot, _T('\\')); + LPTSTR pstrFront = (LPTSTR)_cstrrchr(m_lpszRoot, _T('/')); + + if(pstrFront != NULL || pstrBack != NULL) + { + if(pstrFront == NULL) + pstrFront = m_lpszRoot; + if(pstrBack == NULL) + pstrBack = m_lpszRoot; + + // from the start to the last whack is the root + + if(pstrFront >= pstrBack) + *pstrFront = _T('\0'); + else + *pstrBack = _T('\0'); + } + } + + m_bFound = TRUE; + + return TRUE; + } + + BOOL FindNextFile() + { + ATLASSERT(m_hFind != NULL); + + if(m_hFind == NULL) + return FALSE; + + if(!m_bFound) + return FALSE; + + m_bFound = ::FindNextFile(m_hFind, &m_fd); + + return m_bFound; + } + + void Close() + { + m_bFound = FALSE; + + if(m_hFind != NULL && m_hFind != INVALID_HANDLE_VALUE) + { + ::FindClose(m_hFind); + m_hFind = NULL; + } + } + +// Helper + static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch) + { +#ifdef _ATL_MIN_CRT + const TCHAR* lpsz = NULL; + while (*p != 0) + { + if (*p == ch) + lpsz = p; + p = ::CharNext(p); + } + return lpsz; +#else // !_ATL_MIN_CRT + return _tcsrchr(p, ch); +#endif // !_ATL_MIN_CRT + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Global functions for loading resources + +inline HACCEL AtlLoadAccelerators(ATL::_U_STRINGorID table) +{ + return ::LoadAccelerators(ModuleHelper::GetResourceInstance(), table.m_lpstr); +} + +inline HMENU AtlLoadMenu(ATL::_U_STRINGorID menu) +{ + return ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr); +} + +inline HBITMAP AtlLoadBitmap(ATL::_U_STRINGorID bitmap) +{ + return ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr); +} + +#ifdef OEMRESOURCE +inline HBITMAP AtlLoadSysBitmap(ATL::_U_STRINGorID bitmap) +{ +#ifdef _DEBUG + WORD wID = (WORD)bitmap.m_lpstr; + ATLASSERT(wID >= 32734 && wID <= 32767); +#endif // _DEBUG + return ::LoadBitmap(NULL, bitmap.m_lpstr); +} +#endif // OEMRESOURCE + +inline HCURSOR AtlLoadCursor(ATL::_U_STRINGorID cursor) +{ + return ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr); +} + +inline HCURSOR AtlLoadSysCursor(LPCTSTR lpCursorName) +{ +#if (WINVER >= 0x0500) + ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT || + lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE || + lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW || + lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL || + lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP || + lpCursorName == IDC_HAND); +#else // !(WINVER >= 0x0500) + ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT || + lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE || + lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW || + lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL || + lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP); +#endif // !(WINVER >= 0x0500) + return ::LoadCursor(NULL, lpCursorName); +} + +inline HICON AtlLoadIcon(ATL::_U_STRINGorID icon) +{ + return ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); +} + +#ifndef _WIN32_WCE +inline HICON AtlLoadSysIcon(LPCTSTR lpIconName) +{ +#if (WINVER >= 0x0600) + ATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION || + lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO || + lpIconName == IDI_SHIELD); +#else // !(WINVER >= 0x0600) + ATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION || + lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO); +#endif // !(WINVER >= 0x0600) + return ::LoadIcon(NULL, lpIconName); +} +#endif // !_WIN32_WCE + +inline HBITMAP AtlLoadBitmapImage(ATL::_U_STRINGorID bitmap, UINT fuLoad = LR_DEFAULTCOLOR) +{ + return (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, IMAGE_BITMAP, 0, 0, fuLoad); +} + +inline HCURSOR AtlLoadCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) +{ + return (HCURSOR)::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); +} + +inline HICON AtlLoadIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) +{ + return (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); +} + +#ifdef OEMRESOURCE +inline HBITMAP AtlLoadSysBitmapImage(WORD wBitmapID, UINT fuLoad = LR_DEFAULTCOLOR) +{ + ATLASSERT(wBitmapID >= 32734 && wBitmapID <= 32767); + ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file + return (HBITMAP)::LoadImage(NULL, MAKEINTRESOURCE(wBitmapID), IMAGE_BITMAP, 0, 0, fuLoad); +} +#endif // OEMRESOURCE + +inline HCURSOR AtlLoadSysCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) +{ +#ifdef _DEBUG + WORD wID = (WORD)cursor.m_lpstr; + ATLASSERT((wID >= 32512 && wID <= 32516) || (wID >= 32640 && wID <= 32648) || (wID == 32650) || (wID == 32651)); + ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file +#endif // _DEBUG + return (HCURSOR)::LoadImage(NULL, cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); +} + +inline HICON AtlLoadSysIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) +{ +#ifdef _DEBUG + WORD wID = (WORD)icon.m_lpstr; + ATLASSERT(wID >= 32512 && wID <= 32517); + ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file +#endif // _DEBUG + return (HICON)::LoadImage(NULL, icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); +} + +#if (_ATL_VER < 0x0700) +inline int AtlLoadString(UINT uID, LPTSTR lpBuffer, int nBufferMax) +{ + return ::LoadString(_Module.GetResourceInstance(), uID, lpBuffer, nBufferMax); +} +#endif // (_ATL_VER < 0x0700) + +#ifdef _WIN32_WCE // CE only direct access to the resource +inline LPCTSTR AtlLoadString(UINT uID) +{ + LPCTSTR s = (LPCTSTR)::LoadString(ModuleHelper::GetResourceInstance(), uID, NULL, 0); +#ifdef DEBUG // Check for null-termination + if(s != NULL) + // Note: RC -n compiles null-terminated resource strings + ATLASSERT(s[*((WORD*)s -1) - 1] == L'\0'); +#endif + return s; +} +#endif // _WIN32_WCE + +inline bool AtlLoadString(UINT uID, BSTR& bstrText) +{ + USES_CONVERSION; + ATLASSERT(bstrText == NULL); + + LPTSTR lpstrText = NULL; + int nRes = 0; + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrText = new TCHAR[nLen]); + if(lpstrText == NULL) + break; + nRes = ::LoadString(ModuleHelper::GetResourceInstance(), uID, lpstrText, nLen); + if(nRes < nLen - 1) + break; + delete [] lpstrText; + lpstrText = NULL; + } + + if(lpstrText != NULL) + { + if(nRes != 0) + bstrText = ::SysAllocString(T2OLE(lpstrText)); + delete [] lpstrText; + } + + return (bstrText != NULL) ? true : false; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Global functions for stock GDI objects + +inline HPEN AtlGetStockPen(int nPen) +{ +#if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE) + ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN); +#else + ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN); +#endif + return (HPEN)::GetStockObject(nPen); +} + +inline HBRUSH AtlGetStockBrush(int nBrush) +{ +#if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE) + ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH); +#else + ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH); +#endif + return (HBRUSH)::GetStockObject(nBrush); +} + +inline HFONT AtlGetStockFont(int nFont) +{ +#ifndef _WIN32_WCE + ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT); +#else // CE specific + ATLASSERT(nFont == SYSTEM_FONT); +#endif // _WIN32_WCE + return (HFONT)::GetStockObject(nFont); +} + +inline HPALETTE AtlGetStockPalette(int nPalette) +{ + ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported + return (HPALETTE)::GetStockObject(nPalette); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Global function for compacting a path by replacing parts with ellipsis + +// helper for multi-byte character sets +inline bool _IsDBCSTrailByte(LPCTSTR lpstr, int nChar) +{ +#ifndef _UNICODE + int i = nChar; + for( ; i > 0; i--) + { + if(!::IsDBCSLeadByte(lpstr[i - 1])) + break; + } + return ((nChar > 0) && (((nChar - i) & 1) != 0)); +#else // _UNICODE + lpstr; nChar; + return false; +#endif // _UNICODE +} + +inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen) +{ + ATLASSERT(lpstrOut != NULL); + ATLASSERT(lpstrIn != NULL); + ATLASSERT(cchLen > 0); + + LPCTSTR szEllipsis = _T("..."); + const int cchEndEllipsis = 3; + const int cchMidEllipsis = 4; + + if(lstrlen(lpstrIn) < cchLen) + { + SecureHelper::strcpy_x(lpstrOut, cchLen, lpstrIn); + return true; + } + + lpstrOut[0] = 0; + + // check if the separator is a slash or a backslash + TCHAR chSlash = _T('\\'); + for(LPTSTR lpstr = (LPTSTR)lpstrIn; *lpstr != 0; lpstr = ::CharNext(lpstr)) + { + if((*lpstr == _T('/')) || (*lpstr == _T('\\'))) + chSlash = *lpstr; + } + + // find the filename portion of the path + LPCTSTR lpstrFileName = lpstrIn; + for(LPCTSTR pPath = lpstrIn; *pPath; pPath = ::CharNext(pPath)) + { + if((pPath[0] == _T('\\') || pPath[0] == _T(':') || pPath[0] == _T('/')) + && pPath[1] && pPath[1] != _T('\\') && pPath[1] != _T('/')) + lpstrFileName = pPath + 1; + } + int cchFileName = lstrlen(lpstrFileName); + + // handle just the filename without a path + if(lpstrFileName == lpstrIn && cchLen > cchEndEllipsis) + { + bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchLen - cchEndEllipsis - 1) == 0); + if(bRet) + { +#ifndef _UNICODE + if(_IsDBCSTrailByte(lpstrIn, cchLen - cchEndEllipsis)) + lpstrOut[cchLen - cchEndEllipsis - 1] = 0; +#endif // _UNICODE + SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis); + } + return bRet; + } + + // handle just ellipsis + if((cchLen < (cchMidEllipsis + cchEndEllipsis))) + { + for(int i = 0; i < cchLen - 1; i++) + lpstrOut[i] = ((i + 1) == cchMidEllipsis) ? chSlash : _T('.'); + lpstrOut[cchLen - 1] = 0; + return true; + } + + // calc how much we have to copy + int cchToCopy = cchLen - (cchMidEllipsis + cchFileName) - 1; + + if(cchToCopy < 0) + cchToCopy = 0; + +#ifndef _UNICODE + if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrIn, cchToCopy)) + cchToCopy--; +#endif // _UNICODE + + bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchToCopy) == 0); + if(!bRet) + return false; + + // add ellipsis + SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis); + if(!bRet) + return false; + TCHAR szSlash[2] = { chSlash, 0 }; + SecureHelper::strcat_x(lpstrOut, cchLen, szSlash); + if(!bRet) + return false; + + // add filename (and ellipsis, if needed) + if(cchLen > (cchMidEllipsis + cchFileName)) + { + SecureHelper::strcat_x(lpstrOut, cchLen, lpstrFileName); + } + else + { + cchToCopy = cchLen - cchMidEllipsis - cchEndEllipsis - 1; +#ifndef _UNICODE + if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrFileName, cchToCopy)) + cchToCopy--; +#endif // _UNICODE + bRet = (SecureHelper::strncpy_x(&lpstrOut[cchMidEllipsis], cchLen - cchMidEllipsis, lpstrFileName, cchToCopy) == 0); + if(bRet) + SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis); + } + + return bRet; +} + +}; // namespace WTL + +#endif // __ATLMISC_H__ diff --git a/wtl/wtl/include/atlprint.h b/wtl/wtl/include/atlprint.h new file mode 100644 index 00000000..fed9a3fb --- /dev/null +++ b/wtl/wtl/include/atlprint.h @@ -0,0 +1,1113 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLPRINT_H__ +#define __ATLPRINT_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifdef _WIN32_WCE + #error atlprint.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atlprint.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlprint.h requires atlwin.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CPrinterInfo +// CPrinterT +// CDevModeT +// CPrinterDC +// CPrintJobInfo +// CPrintJob +// CPrintPreview +// CPrintPreviewWindowImpl +// CPrintPreviewWindow +// CZoomPrintPreviewWindowImpl +// CZoomPrintPreviewWindow + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures +// and provided by ::GetPrinter. + +template +class _printer_info +{ +public: + typedef void infotype; +}; + +template <> class _printer_info<1> { public: typedef PRINTER_INFO_1 infotype; }; +template <> class _printer_info<2> { public: typedef PRINTER_INFO_2 infotype; }; +template <> class _printer_info<3> { public: typedef PRINTER_INFO_3 infotype; }; +template <> class _printer_info<4> { public: typedef PRINTER_INFO_4 infotype; }; +template <> class _printer_info<5> { public: typedef PRINTER_INFO_5 infotype; }; +template <> class _printer_info<6> { public: typedef PRINTER_INFO_6 infotype; }; +template <> class _printer_info<7> { public: typedef PRINTER_INFO_7 infotype; }; +// these are not in the old (vc6.0) headers +#ifdef _ATL_USE_NEW_PRINTER_INFO +template <> class _printer_info<8> { public: typedef PRINTER_INFO_8 infotype; }; +template <> class _printer_info<9> { public: typedef PRINTER_INFO_9 infotype; }; +#endif // _ATL_USE_NEW_PRINTER_INFO + + +template +class CPrinterInfo +{ +public: +// Data members + typename _printer_info::infotype* m_pi; + +// Constructor/destructor + CPrinterInfo() : m_pi(NULL) + { } + + CPrinterInfo(HANDLE hPrinter) : m_pi(NULL) + { + GetPrinterInfo(hPrinter); + } + + ~CPrinterInfo() + { + Cleanup(); + } + +// Operations + bool GetPrinterInfo(HANDLE hPrinter) + { + Cleanup(); + return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo); + } + +// Implementation + void Cleanup() + { + delete [] (BYTE*)m_pi; + m_pi = NULL; + } + + static bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex) + { + ATLASSERT(pi != NULL); + DWORD dw = 0; + BYTE* pb = NULL; + ::GetPrinter(hPrinter, nIndex, NULL, 0, &dw); + if (dw > 0) + { + ATLTRY(pb = new BYTE[dw]); + if (pb != NULL) + { + memset(pb, 0, dw); + DWORD dwNew; + if (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew)) + { + delete [] pb; + pb = NULL; + } + } + } + *pi = pb; + return (pb != NULL); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrinter - Wrapper class for a HANDLE to a printer + +template +class CPrinterT +{ +public: +// Data members + HANDLE m_hPrinter; + +// Constructor/destructor + CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter) + { } + + ~CPrinterT() + { + ClosePrinter(); + } + +// Operations + CPrinterT& operator =(HANDLE hPrinter) + { + if (hPrinter != m_hPrinter) + { + ClosePrinter(); + m_hPrinter = hPrinter; + } + return *this; + } + + bool IsNull() const { return (m_hPrinter == NULL); } + + bool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL) + { + bool b = false; + DEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames); + if (pdn != NULL) + { + LPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset; + b = OpenPrinter(lpszPrinterName, pDevMode); + ::GlobalUnlock(hDevNames); + } + return b; + } + + bool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL) + { + ClosePrinter(); + PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; + ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); + + return (m_hPrinter != NULL); + } + + bool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs) + { + ClosePrinter(); + ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs); + return (m_hPrinter != NULL); + } + + bool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL) + { + ClosePrinter(); + const int cchBuff = 512; + TCHAR buffer[cchBuff]; + buffer[0] = 0; + ::GetProfileString(_T("windows"), _T("device"), _T(",,,"), buffer, cchBuff); + int nLen = lstrlen(buffer); + if (nLen != 0) + { + LPTSTR lpsz = buffer; + while (*lpsz) + { + if (*lpsz == _T(',')) + { + *lpsz = 0; + break; + } + lpsz = CharNext(lpsz); + } + PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; + ::OpenPrinter(buffer, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); + } + return m_hPrinter != NULL; + } + + void ClosePrinter() + { + if (m_hPrinter != NULL) + { + if (t_bManaged) + ::ClosePrinter(m_hPrinter); + m_hPrinter = NULL; + } + } + + bool PrinterProperties(HWND hWnd = NULL) + { + if (hWnd == NULL) + hWnd = ::GetActiveWindow(); + return !!::PrinterProperties(hWnd, m_hPrinter); + } + + HANDLE CopyToHDEVNAMES() const + { + HANDLE h = NULL; + CPrinterInfo<5> pinfon5; + CPrinterInfo<2> pinfon2; + LPTSTR lpszPrinterName = NULL; + // Some printers fail for PRINTER_INFO_5 in some situations + if (pinfon5.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfon5.m_pi->pPrinterName; + else if (pinfon2.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfon2.m_pi->pPrinterName; + if (lpszPrinterName != NULL) + { + int nLen = sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR); + h = ::GlobalAlloc(GMEM_MOVEABLE, nLen); + BYTE* pv = (BYTE*)::GlobalLock(h); + DEVNAMES* pdev = (DEVNAMES*)pv; + if (pv != NULL) + { + memset(pv, 0, nLen); + pdev->wDeviceOffset = sizeof(DEVNAMES) / sizeof(TCHAR); + pv = pv + sizeof(DEVNAMES); // now points to end + SecureHelper::strcpy_x((LPTSTR)pv, lstrlen(lpszPrinterName) + 1, lpszPrinterName); + ::GlobalUnlock(h); + } + } + return h; + } + + HDC CreatePrinterDC(const DEVMODE* pdm = NULL) const + { + CPrinterInfo<5> pinfo5; + CPrinterInfo<2> pinfo2; + HDC hDC = NULL; + LPTSTR lpszPrinterName = NULL; + // Some printers fail for PRINTER_INFO_5 in some situations + if (pinfo5.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfo5.m_pi->pPrinterName; + else if (pinfo2.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfo2.m_pi->pPrinterName; + if (lpszPrinterName != NULL) + hDC = ::CreateDC(NULL, lpszPrinterName, NULL, pdm); + return hDC; + } + + HDC CreatePrinterIC(const DEVMODE* pdm = NULL) const + { + CPrinterInfo<5> pinfo5; + CPrinterInfo<2> pinfo2; + HDC hDC = NULL; + LPTSTR lpszPrinterName = NULL; + // Some printers fail for PRINTER_INFO_5 in some situations + if (pinfo5.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfo5.m_pi->pPrinterName; + else if (pinfo2.GetPrinterInfo(m_hPrinter)) + lpszPrinterName = pinfo2.m_pi->pPrinterName; + if (lpszPrinterName != NULL) + hDC = ::CreateIC(NULL, lpszPrinterName, NULL, pdm); + return hDC; + } + + void Attach(HANDLE hPrinter) + { + ClosePrinter(); + m_hPrinter = hPrinter; + } + + HANDLE Detach() + { + HANDLE hPrinter = m_hPrinter; + m_hPrinter = NULL; + return hPrinter; + } + + operator HANDLE() const { return m_hPrinter; } +}; + +typedef CPrinterT CPrinterHandle; +typedef CPrinterT CPrinter; + + +/////////////////////////////////////////////////////////////////////////////// +// CDevMode - Wrapper class for DEVMODE + +template +class CDevModeT +{ +public: +// Data members + HANDLE m_hDevMode; + DEVMODE* m_pDevMode; + +// Constructor/destructor + CDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode) + { + m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; + } + + ~CDevModeT() + { + Cleanup(); + } + +// Operations + CDevModeT& operator =(HANDLE hDevMode) + { + Attach(hDevMode); + return *this; + } + + void Attach(HANDLE hDevModeNew) + { + Cleanup(); + m_hDevMode = hDevModeNew; + m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; + } + + HANDLE Detach() + { + if (m_hDevMode != NULL) + ::GlobalUnlock(m_hDevMode); + HANDLE hDevMode = m_hDevMode; + m_hDevMode = NULL; + return hDevMode; + } + + bool IsNull() const { return (m_hDevMode == NULL); } + + bool CopyFromPrinter(HANDLE hPrinter) + { + CPrinterInfo<2> pinfo; + bool b = pinfo.GetPrinterInfo(hPrinter); + if (b) + b = CopyFromDEVMODE(pinfo.m_pi->pDevMode); + return b; + } + + bool CopyFromDEVMODE(const DEVMODE* pdm) + { + if (pdm == NULL) + return false; + int nSize = pdm->dmSize + pdm->dmDriverExtra; + HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); + if (h != NULL) + { + void* p = ::GlobalLock(h); + SecureHelper::memcpy_x(p, nSize, pdm, nSize); + ::GlobalUnlock(h); + } + Attach(h); + return (h != NULL); + } + + bool CopyFromHDEVMODE(HANDLE hdm) + { + bool b = false; + if (hdm != NULL) + { + DEVMODE* pdm = (DEVMODE*)::GlobalLock(hdm); + b = CopyFromDEVMODE(pdm); + ::GlobalUnlock(hdm); + } + return b; + } + + HANDLE CopyToHDEVMODE() + { + if ((m_hDevMode == NULL) || (m_pDevMode == NULL)) + return NULL; + int nSize = m_pDevMode->dmSize + m_pDevMode->dmDriverExtra; + HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); + if (h != NULL) + { + void* p = ::GlobalLock(h); + SecureHelper::memcpy_x(p, nSize, m_pDevMode, nSize); + ::GlobalUnlock(h); + } + return h; + } + + // If this devmode was for another printer, this will create a new devmode + // based on the existing devmode, but retargeted at the new printer + bool UpdateForNewPrinter(HANDLE hPrinter) + { + bool bRet = false; + LONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0); + CTempBuffer buff; + DEVMODE* pdm = buff.AllocateBytes(nLen); + if(pdm != NULL) + { + memset(pdm, 0, nLen); + LONG l = ::DocumentProperties(NULL, hPrinter, NULL, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); + if (l == IDOK) + bRet = CopyFromDEVMODE(pdm); + } + + return bRet; + } + + bool DocumentProperties(HANDLE hPrinter, HWND hWnd = NULL) + { + CPrinterInfo<1> pi; + pi.GetPrinterInfo(hPrinter); + if (hWnd == NULL) + hWnd = ::GetActiveWindow(); + + bool bRet = false; + LONG nLen = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, NULL, NULL, 0); + CTempBuffer buff; + DEVMODE* pdm = buff.AllocateBytes(nLen); + if(pdm != NULL) + { + memset(pdm, 0, nLen); + LONG l = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER | DM_PROMPT); + if (l == IDOK) + bRet = CopyFromDEVMODE(pdm); + } + + return bRet; + } + + operator HANDLE() const { return m_hDevMode; } + + operator DEVMODE*() const { return m_pDevMode; } + +// Implementation + void Cleanup() + { + if (m_hDevMode != NULL) + { + ::GlobalUnlock(m_hDevMode); + if(t_bManaged) + ::GlobalFree(m_hDevMode); + m_hDevMode = NULL; + } + } +}; + +typedef CDevModeT CDevModeHandle; +typedef CDevModeT CDevMode; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrinterDC + +class CPrinterDC : public CDC +{ +public: +// Constructors/destructor + CPrinterDC() + { + CPrinter printer; + printer.OpenDefaultPrinter(); + Attach(printer.CreatePrinterDC()); + ATLASSERT(m_hDC != NULL); + } + + CPrinterDC(HANDLE hPrinter, const DEVMODE* pdm = NULL) + { + CPrinterHandle p; + p.Attach(hPrinter); + Attach(p.CreatePrinterDC(pdm)); + ATLASSERT(m_hDC != NULL); + } + + ~CPrinterDC() + { + DeleteDC(); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintJob - Wraps a set of tasks for a specific printer (StartDoc/EndDoc) +// Handles aborting, background printing + +// Defines callbacks used by CPrintJob (not a COM interface) +class ATL_NO_VTABLE IPrintJobInfo +{ +public: + virtual void BeginPrintJob(HDC hDC) = 0; // allocate handles needed, etc. + virtual void EndPrintJob(HDC hDC, bool bAborted) = 0; // free handles, etc. + virtual void PrePrintPage(UINT nPage, HDC hDC) = 0; + virtual bool PrintPage(UINT nPage, HDC hDC) = 0; + virtual void PostPrintPage(UINT nPage, HDC hDC) = 0; + // If you want per page devmodes, return the DEVMODE* to use for nPage. + // You can optimize by only returning a new DEVMODE* when it is different + // from the one for nLastPage, otherwise return NULL. + // When nLastPage==0, the current DEVMODE* will be the default passed to + // StartPrintJob. + // Note: During print preview, nLastPage will always be "0". + virtual DEVMODE* GetNewDevModeForPage(UINT nLastPage, UINT nPage) = 0; + virtual bool IsValidPage(UINT nPage) = 0; +}; + +// Provides a default implementatin for IPrintJobInfo +// Typically, MI'd into a document or view class +class ATL_NO_VTABLE CPrintJobInfo : public IPrintJobInfo +{ +public: + virtual void BeginPrintJob(HDC /*hDC*/) // allocate handles needed, etc + { + } + + virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/) // free handles, etc + { + } + + virtual void PrePrintPage(UINT /*nPage*/, HDC hDC) + { + m_nPJState = ::SaveDC(hDC); + } + + virtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0; + + virtual void PostPrintPage(UINT /*nPage*/, HDC hDC) + { + RestoreDC(hDC, m_nPJState); + } + + virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/) + { + return NULL; + } + + virtual bool IsValidPage(UINT /*nPage*/) + { + return true; + } + +// Implementation - data + int m_nPJState; +}; + + +class CPrintJob +{ +public: +// Data members + CPrinterHandle m_printer; + IPrintJobInfo* m_pInfo; + DEVMODE* m_pDefDevMode; + DOCINFO m_docinfo; + int m_nJobID; + bool m_bCancel; + bool m_bComplete; + unsigned long m_nStartPage; + unsigned long m_nEndPage; + +// Constructor/destructor + CPrintJob() : m_nJobID(0), m_bCancel(false), m_bComplete(true) + { } + + ~CPrintJob() + { + ATLASSERT(IsJobComplete()); // premature destruction? + } + +// Operations + bool IsJobComplete() const + { + return m_bComplete; + } + + bool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode, + IPrintJobInfo* pInfo, LPCTSTR lpszDocName, + unsigned long nStartPage, unsigned long nEndPage, + bool bPrintToFile = false, LPCTSTR lpstrOutputFile = NULL) + { + ATLASSERT(m_bComplete); // previous job not done yet? + if (pInfo == NULL) + return false; + + memset(&m_docinfo, 0, sizeof(m_docinfo)); + m_docinfo.cbSize = sizeof(m_docinfo); + m_docinfo.lpszDocName = lpszDocName; + m_pInfo = pInfo; + m_nStartPage = nStartPage; + m_nEndPage = nEndPage; + m_printer.Attach(hPrinter); + m_pDefDevMode = pDefaultDevMode; + m_bComplete = false; + + if(bPrintToFile) + m_docinfo.lpszOutput = (lpstrOutputFile != NULL) ? lpstrOutputFile : _T("FILE:"); + + if (!bBackground) + { + m_bComplete = true; + return StartHelper(); + } + + // Create a thread and return + DWORD dwThreadID = 0; +#if !defined(_ATL_MIN_CRT) && defined(_MT) + HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))StartProc, this, 0, (UINT*)&dwThreadID); +#else + HANDLE hThread = ::CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID); +#endif + if (hThread == NULL) + return false; + + ::CloseHandle(hThread); + + return true; + } + +// Implementation + static DWORD WINAPI StartProc(void* p) + { + CPrintJob* pThis = (CPrintJob*)p; + pThis->StartHelper(); + pThis->m_bComplete = true; + return 0; + } + + bool StartHelper() + { + CDC dcPrinter; + dcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode)); + if (dcPrinter.IsNull()) + return false; + + m_nJobID = ::StartDoc(dcPrinter, &m_docinfo); + if (m_nJobID <= 0) + return false; + + m_pInfo->BeginPrintJob(dcPrinter); + + // print all the pages now + unsigned long nLastPage = 0; + for (unsigned long nPage = m_nStartPage; nPage <= m_nEndPage; nPage++) + { + if (!m_pInfo->IsValidPage(nPage)) + break; + DEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage); + if (pdm != NULL) + dcPrinter.ResetDC(pdm); + dcPrinter.StartPage(); + m_pInfo->PrePrintPage(nPage, dcPrinter); + if (!m_pInfo->PrintPage(nPage, dcPrinter)) + m_bCancel = true; + m_pInfo->PostPrintPage(nPage, dcPrinter); + dcPrinter.EndPage(); + if (m_bCancel) + break; + nLastPage = nPage; + } + + m_pInfo->EndPrintJob(dcPrinter, m_bCancel); + if (m_bCancel) + ::AbortDoc(dcPrinter); + else + ::EndDoc(dcPrinter); + m_nJobID = 0; + return true; + } + + // Cancels a print job. Can be called asynchronously. + void CancelPrintJob() + { + m_bCancel = true; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintPreview - Adds print preview support to an existing window + +class CPrintPreview +{ +public: +// Data members + IPrintJobInfo* m_pInfo; + CPrinterHandle m_printer; + CEnhMetaFile m_meta; + DEVMODE* m_pDefDevMode; + DEVMODE* m_pCurDevMode; + SIZE m_sizeCurPhysOffset; + +// Constructor + CPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL) + { + m_sizeCurPhysOffset.cx = 0; + m_sizeCurPhysOffset.cy = 0; + } + +// Operations + void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji) + { + m_printer.Attach(hPrinter); + m_pDefDevMode = pDefaultDevMode; + m_pInfo = pji; + m_nCurPage = 0; + m_pCurDevMode = NULL; + } + + void SetEnhMetaFile(HENHMETAFILE hEMF) + { + m_meta = hEMF; + } + + void SetPage(int nPage) + { + if (!m_pInfo->IsValidPage(nPage)) + return; + m_nCurPage = nPage; + m_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage); + if (m_pCurDevMode == NULL) + m_pCurDevMode = m_pDefDevMode; + CDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode); + + int iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH); + int iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT); + int nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX); + int nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY); + + RECT rcMM = { 0, 0, ::MulDiv(iWidth, 2540, nLogx), ::MulDiv(iHeight, 2540, nLogy) }; + + m_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX); + m_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY); + + CEnhMetaFileDC dcMeta(dcPrinter, &rcMM); + m_pInfo->PrePrintPage(nPage, dcMeta); + m_pInfo->PrintPage(nPage, dcMeta); + m_pInfo->PostPrintPage(nPage, dcMeta); + m_meta.Attach(dcMeta.Close()); + } + + void GetPageRect(RECT& rc, LPRECT prc) + { + int x1 = rc.right-rc.left; + int y1 = rc.bottom - rc.top; + if ((x1 < 0) || (y1 < 0)) + return; + + CEnhMetaFileInfo emfinfo(m_meta); + ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); + + // Compute whether we are OK vertically or horizontally + int x2 = pmh->szlDevice.cx; + int y2 = pmh->szlDevice.cy; + int y1p = MulDiv(x1, y2, x2); + int x1p = MulDiv(y1, x2, y2); + ATLASSERT((x1p <= x1) || (y1p <= y1)); + if (x1p <= x1) + { + prc->left = rc.left + (x1 - x1p) / 2; + prc->right = prc->left + x1p; + prc->top = rc.top; + prc->bottom = rc.bottom; + } + else + { + prc->left = rc.left; + prc->right = rc.right; + prc->top = rc.top + (y1 - y1p) / 2; + prc->bottom = prc->top + y1p; + } + } + +// Painting helpers + void DoPaint(CDCHandle dc) + { + // this one is not used + } + + void DoPaint(CDCHandle dc, RECT& rc) + { + CEnhMetaFileInfo emfinfo(m_meta); + ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); + int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); + int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); + + dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); + dc.PlayMetaFile(m_meta, &rc); + } + +// Implementation - data + int m_nCurPage; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CPrintPreviewWindow - Implements a print preview window + +template +class ATL_NO_VTABLE CPrintPreviewWindowImpl : public ATL::CWindowImpl, public CPrintPreview +{ +public: + DECLARE_WND_CLASS_EX(NULL, CS_VREDRAW | CS_HREDRAW, -1) + + enum { m_cxOffset = 10, m_cyOffset = 10 }; + +// Constructor + CPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(0) + { } + +// Operations + void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, + IPrintJobInfo* pji, int nMinPage, int nMaxPage) + { + CPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji); + m_nMinPage = nMinPage; + m_nMaxPage = nMaxPage; + } + + bool NextPage() + { + if (m_nCurPage == m_nMaxPage) + return false; + SetPage(m_nCurPage + 1); + Invalidate(); + return true; + } + + bool PrevPage() + { + if (m_nCurPage == m_nMinPage) + return false; + if (m_nCurPage == 0) + return false; + SetPage(m_nCurPage - 1); + Invalidate(); + return true; + } + +// Message map and handlers + BEGIN_MSG_MAP(CPrintPreviewWindowImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + END_MSG_MAP() + + LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no need for the background + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + RECT rc = { 0 }; + + if(wParam != NULL) + { + pT->DoPrePaint((HDC)wParam, rc); + pT->DoPaint((HDC)wParam, rc); + } + else + { + CPaintDC dc(m_hWnd); + pT->DoPrePaint(dc.m_hDC, rc); + pT->DoPaint(dc.m_hDC, rc); + } + + return 0; + } + +// Painting helper + void DoPrePaint(CDCHandle dc, RECT& rc) + { + RECT rcClient = { 0 }; + GetClientRect(&rcClient); + RECT rcArea = rcClient; + T* pT = static_cast(this); + pT; // avoid level 4 warning + ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); + if (rcArea.left > rcArea.right) + rcArea.right = rcArea.left; + if (rcArea.top > rcArea.bottom) + rcArea.bottom = rcArea.top; + GetPageRect(rcArea, &rc); + CRgn rgn1, rgn2; + rgn1.CreateRectRgnIndirect(&rc); + rgn2.CreateRectRgnIndirect(&rcClient); + rgn2.CombineRgn(rgn1, RGN_DIFF); + dc.SelectClipRgn(rgn2); + dc.FillRect(&rcClient, COLOR_BTNSHADOW); + dc.SelectClipRgn(NULL); + dc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH)); + } + +// Implementation - data + int m_nMinPage; + int m_nMaxPage; +}; + + +class CPrintPreviewWindow : public CPrintPreviewWindowImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_PrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CZoomPrintPreviewWindowImpl - Implements print preview window with zooming + +#ifdef __ATLSCRL_H__ + +template +class ATL_NO_VTABLE CZoomPrintPreviewWindowImpl : public CPrintPreviewWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T > +{ +public: + bool m_bSized; + + CZoomPrintPreviewWindowImpl() + { + SetScrollExtendedStyle(SCRL_DISABLENOSCROLL); + InitZoom(); + } + + // should be called to reset data members before recreating window + void InitZoom() + { + m_bSized = false; + m_nZoomMode = ZOOMMODE_OFF; + m_fZoomScaleMin = 1.0; + m_fZoomScale = 1.0; + } + + BEGIN_MSG_MAP(CZoomPrintPreviewWindowImpl) + MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown) + MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + SIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; + POINT ptOffset = m_ptOffset; + SIZE sizeAll = m_sizeAll; + SetScrollSize(sizeClient); + if(sizeAll.cx > 0) + ptOffset.x = ::MulDiv(ptOffset.x, m_sizeAll.cx, sizeAll.cx); + if(sizeAll.cy > 0) + ptOffset.y = ::MulDiv(ptOffset.y, m_sizeAll.cy, sizeAll.cy); + SetScrollOffset(ptOffset); + CScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled); + if(!m_bSized) + { + m_bSized = true; + T* pT = static_cast(this); + pT->ShowScrollBar(SB_HORZ, TRUE); + pT->ShowScrollBar(SB_VERT, TRUE); + } + return 0; + } + + LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + RECT rc = { 0 }; + + if(wParam != NULL) + { + CDCHandle dc = (HDC)wParam; + int nMapModeSav = dc.GetMapMode(); + dc.SetMapMode(MM_ANISOTROPIC); + SIZE szWindowExt = { 0, 0 }; + dc.SetWindowExt(m_sizeLogAll, &szWindowExt); + SIZE szViewportExt = { 0, 0 }; + dc.SetViewportExt(m_sizeAll, &szViewportExt); + POINT ptViewportOrg = { 0, 0 }; + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); + + pT->DoPrePaint(dc, rc); + pT->DoPaint(dc, rc); + + dc.SetMapMode(nMapModeSav); + dc.SetWindowExt(szWindowExt); + dc.SetViewportExt(szViewportExt); + dc.SetViewportOrg(ptViewportOrg); + } + else + { + CPaintDC dc(pT->m_hWnd); + pT->PrepareDC(dc.m_hDC); + pT->DoPrePaint(dc.m_hDC, rc); + pT->DoPaint(dc.m_hDC, rc); + } + + return 0; + } + + // Painting helpers + void DoPaint(CDCHandle dc) + { + // this one is not used + } + + void DoPrePaint(CDCHandle dc, RECT& rc) + { + RECT rcClient; + GetClientRect(&rcClient); + RECT rcArea = rcClient; + T* pT = static_cast(this); + pT; // avoid level 4 warning + ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); + if (rcArea.left > rcArea.right) + rcArea.right = rcArea.left; + if (rcArea.top > rcArea.bottom) + rcArea.bottom = rcArea.top; + GetPageRect(rcArea, &rc); + HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW)); + dc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY); + dc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY); + dc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY); + dc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY); + dc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH)); + dc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY); + dc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW)); + dc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY); + dc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY); + dc.SelectBrush(hbrOld); + } + + void DoPaint(CDCHandle dc, RECT& rc) + { + CEnhMetaFileInfo emfinfo(m_meta); + ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); + int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); + int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); + + dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); + dc.PlayMetaFile(m_meta, &rc); + } +}; + +class CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_ZoomPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) +}; + +#endif // __ATLSCRL_H__ + +}; // namespace WTL + +#endif // __ATLPRINT_H__ diff --git a/wtl/wtl/include/atlres.h b/wtl/wtl/include/atlres.h new file mode 100644 index 00000000..ae058876 --- /dev/null +++ b/wtl/wtl/include/atlres.h @@ -0,0 +1,262 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLRES_H__ +#define __ATLRES_H__ + +#pragma once + +#if defined(_WIN32_WCE) && !defined(__ATLRESCE_H__) + #error Use atlresCE.h instead of atlres.h for Windows CE +#endif + + +#ifdef RC_INVOKED +#ifndef _INC_WINDOWS + + #define _INC_WINDOWS + + #ifndef _WIN32_WCE + #define VS_VERSION_INFO 1 + + #ifdef APSTUDIO_INVOKED + #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols + #endif // APSTUDIO_INVOKED + + #ifndef WINVER + #define WINVER 0x0400 // default to Windows Version 4.0 + #endif // !WINVER + + #include + + // operation messages sent to DLGINIT + #define LB_ADDSTRING (WM_USER+1) + #define CB_ADDSTRING (WM_USER+3) + #endif // !_WIN32_WCE + + #ifdef APSTUDIO_INVOKED + #undef APSTUDIO_HIDDEN_SYMBOLS + #endif // APSTUDIO_INVOKED + + #ifdef IDC_STATIC + #undef IDC_STATIC + #endif // IDC_STATIC + #define IDC_STATIC (-1) + +#endif // !_INC_WINDOWS +#endif // RC_INVOKED + +#ifdef APSTUDIO_INVOKED + #define APSTUDIO_HIDDEN_SYMBOLS +#endif // APSTUDIO_INVOKED + +/////////////////////////////////////////////////////////////////////////////// +// ATL resource types + +#ifndef RC_INVOKED + #define RT_DLGINIT MAKEINTRESOURCE(240) + #define RT_TOOLBAR MAKEINTRESOURCE(241) +#endif // RC_INVOKED + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef APSTUDIO_INVOKED + #undef APSTUDIO_HIDDEN_SYMBOLS +#endif // APSTUDIO_INVOKED + +/////////////////////////////////////////////////////////////////////////////// +// Standard window components + +#define ID_SEPARATOR 0 // special separator value +#define ID_DEFAULT_PANE 0 // default status bar pane + +#ifndef RC_INVOKED // code only +// standard control bars (IDW = window ID) + #define ATL_IDW_TOOLBAR 0xE800 // main Toolbar for window + #define ATL_IDW_STATUS_BAR 0xE801 // Status bar window + #define ATL_IDW_COMMAND_BAR 0xE802 // Command bar window + +// parts of a frame window + #define ATL_IDW_CLIENT 0xE900 + #define ATL_IDW_PANE_FIRST 0xE900 // first pane (256 max) + #define ATL_IDW_PANE_LAST 0xE9FF + #define ATL_IDW_HSCROLL_FIRST 0xEA00 // first Horz scrollbar (16 max) + #define ATL_IDW_VSCROLL_FIRST 0xEA10 // first Vert scrollbar (16 max) + + #define ATL_IDW_SIZE_BOX 0xEA20 // size box for splitters + #define ATL_IDW_PANE_SAVE 0xEA21 // to shift ATL_IDW_PANE_FIRST + +// bands for a rebar + #define ATL_IDW_BAND_FIRST 0xEB00 + #define ATL_IDW_BAND_LAST 0xEBFF +#endif // !RC_INVOKED + +/////////////////////////////////////////////////////////////////////////////// +// Standard Commands + +// File commands +#define ID_FILE_NEW 0xE100 +#define ID_FILE_OPEN 0xE101 +#define ID_FILE_CLOSE 0xE102 +#define ID_FILE_SAVE 0xE103 +#define ID_FILE_SAVE_AS 0xE104 +#define ID_FILE_PAGE_SETUP 0xE105 +#define ID_FILE_PRINT_SETUP 0xE106 +#define ID_FILE_PRINT 0xE107 +#define ID_FILE_PRINT_DIRECT 0xE108 +#define ID_FILE_PRINT_PREVIEW 0xE109 +#define ID_FILE_UPDATE 0xE10A +#define ID_FILE_SAVE_COPY_AS 0xE10B +#define ID_FILE_SEND_MAIL 0xE10C + +#define ID_FILE_MRU_FIRST 0xE110 +#define ID_FILE_MRU_FILE1 0xE110 // range - 16 max +#define ID_FILE_MRU_FILE2 0xE111 +#define ID_FILE_MRU_FILE3 0xE112 +#define ID_FILE_MRU_FILE4 0xE113 +#define ID_FILE_MRU_FILE5 0xE114 +#define ID_FILE_MRU_FILE6 0xE115 +#define ID_FILE_MRU_FILE7 0xE116 +#define ID_FILE_MRU_FILE8 0xE117 +#define ID_FILE_MRU_FILE9 0xE118 +#define ID_FILE_MRU_FILE10 0xE119 +#define ID_FILE_MRU_FILE11 0xE11A +#define ID_FILE_MRU_FILE12 0xE11B +#define ID_FILE_MRU_FILE13 0xE11C +#define ID_FILE_MRU_FILE14 0xE11D +#define ID_FILE_MRU_FILE15 0xE11E +#define ID_FILE_MRU_FILE16 0xE11F +#define ID_FILE_MRU_LAST 0xE11F + +// Edit commands +#define ID_EDIT_CLEAR 0xE120 +#define ID_EDIT_CLEAR_ALL 0xE121 +#define ID_EDIT_COPY 0xE122 +#define ID_EDIT_CUT 0xE123 +#define ID_EDIT_FIND 0xE124 +#define ID_EDIT_PASTE 0xE125 +#define ID_EDIT_PASTE_LINK 0xE126 +#define ID_EDIT_PASTE_SPECIAL 0xE127 +#define ID_EDIT_REPEAT 0xE128 +#define ID_EDIT_REPLACE 0xE129 +#define ID_EDIT_SELECT_ALL 0xE12A +#define ID_EDIT_UNDO 0xE12B +#define ID_EDIT_REDO 0xE12C + +// Window commands +#define ID_WINDOW_NEW 0xE130 +#define ID_WINDOW_ARRANGE 0xE131 +#define ID_WINDOW_CASCADE 0xE132 +#define ID_WINDOW_TILE_HORZ 0xE133 +#define ID_WINDOW_TILE_VERT 0xE134 +#define ID_WINDOW_SPLIT 0xE135 +#ifndef RC_INVOKED // code only + #define ATL_IDM_WINDOW_FIRST 0xE130 + #define ATL_IDM_WINDOW_LAST 0xE13F + #define ATL_IDM_FIRST_MDICHILD 0xFF00 // window list starts here + #define ATL_IDM_LAST_MDICHILD 0xFFFD +#endif // !RC_INVOKED +// TabView +#define ID_WINDOW_TABFIRST 0xFF00 // = ATL_IDM_FIRST_MDICHILD +#define ID_WINDOW_TABLAST 0xFFFD +#define ID_WINDOW_SHOWTABLIST 0xFFFE + +// Help and App commands +#define ID_APP_ABOUT 0xE140 +#define ID_APP_EXIT 0xE141 +#define ID_HELP_INDEX 0xE142 +#define ID_HELP_FINDER 0xE143 +#define ID_HELP_USING 0xE144 +#define ID_CONTEXT_HELP 0xE145 // shift-F1 +// special commands for processing help +#define ID_HELP 0xE146 // first attempt for F1 +#define ID_DEFAULT_HELP 0xE147 // last attempt + +// Misc +#define ID_NEXT_PANE 0xE150 +#define ID_PREV_PANE 0xE151 +#define ID_PANE_CLOSE 0xE152 + +// Format +#define ID_FORMAT_FONT 0xE160 + +// Scroll +#define ID_SCROLL_UP 0xE170 +#define ID_SCROLL_DOWN 0xE171 +#define ID_SCROLL_PAGE_UP 0xE172 +#define ID_SCROLL_PAGE_DOWN 0xE173 +#define ID_SCROLL_TOP 0xE174 +#define ID_SCROLL_BOTTOM 0xE175 +#define ID_SCROLL_LEFT 0xE176 +#define ID_SCROLL_RIGHT 0xE177 +#define ID_SCROLL_PAGE_LEFT 0xE178 +#define ID_SCROLL_PAGE_RIGHT 0xE179 +#define ID_SCROLL_ALL_LEFT 0xE17A +#define ID_SCROLL_ALL_RIGHT 0xE17B + +// OLE commands +#define ID_OLE_INSERT_NEW 0xE200 +#define ID_OLE_EDIT_LINKS 0xE201 +#define ID_OLE_EDIT_CONVERT 0xE202 +#define ID_OLE_EDIT_CHANGE_ICON 0xE203 +#define ID_OLE_EDIT_PROPERTIES 0xE204 +#define ID_OLE_VERB_FIRST 0xE210 // range - 16 max +#ifndef RC_INVOKED // code only + #define ID_OLE_VERB_LAST 0xE21F +#endif // !RC_INVOKED + +// View commands (same number used as IDW used for toolbar and status bar) +#define ID_VIEW_TOOLBAR 0xE800 +#define ID_VIEW_STATUS_BAR 0xE801 +#define ID_VIEW_REFRESH 0xE803 + +/////////////////////////////////////////////////////////////////////////////// +// Standard control IDs + +#ifdef IDC_STATIC + #undef IDC_STATIC +#endif // IDC_STATIC +#define IDC_STATIC (-1) // all static controls + +/////////////////////////////////////////////////////////////////////////////// +// Standard string error/warnings + +// idle status bar message +#define ATL_IDS_IDLEMESSAGE 0xE001 + +#ifndef RC_INVOKED // code only + #define ATL_IDS_SCFIRST 0xEF00 +#endif // !RC_INVOKED + +#define ATL_IDS_SCSIZE 0xEF00 +#define ATL_IDS_SCMOVE 0xEF01 +#define ATL_IDS_SCMINIMIZE 0xEF02 +#define ATL_IDS_SCMAXIMIZE 0xEF03 +#define ATL_IDS_SCNEXTWINDOW 0xEF04 +#define ATL_IDS_SCPREVWINDOW 0xEF05 +#define ATL_IDS_SCCLOSE 0xEF06 +#define ATL_IDS_SCRESTORE 0xEF12 +#define ATL_IDS_SCTASKLIST 0xEF13 + +#define ATL_IDS_MDICHILD 0xEF1F +#define ATL_IDS_MRU_FILE 0xEFDA + +/////////////////////////////////////////////////////////////////////////////// +// Misc. control IDs + +// Property Sheet control id's (determined with Spy++) +#define ID_APPLY_NOW 0x3021 +#define ID_WIZBACK 0x3023 +#define ID_WIZNEXT 0x3024 +#define ID_WIZFINISH 0x3025 +#define ATL_IDC_TAB_CONTROL 0x3020 + +#endif // __ATLRES_H__ diff --git a/wtl/wtl/include/atlresce.h b/wtl/wtl/include/atlresce.h new file mode 100644 index 00000000..64346b1e --- /dev/null +++ b/wtl/wtl/include/atlresce.h @@ -0,0 +1,93 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLRESCE_H__ +#define __ATLRESCE_H__ + +#pragma once + +#ifndef _WIN32_WCE + #error atlresCE.h is only for Windows CE +#endif + + +#ifdef RC_INVOKED +#ifndef _INC_WINDOWS + + #define VS_VERSION_INFO 1 + + #ifdef APSTUDIO_INVOKED + #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols + #endif // APSTUDIO_INVOKED + + #ifndef WINVER + #define WINVER 0x0400 // default to Windows Version 4.0 + #endif // !WINVER + + #if !defined(WCEOLE_ENABLE_DIALOGEX) + #define DIALOGEX DIALOG DISCARDABLE + #endif + + #include + #define SHMENUBAR RCDATA + + #if defined(SHELLSDK_MODULES_AYGSHELL) + #include + #else + #define NOMENU 0xFFFF + #define IDS_SHNEW 1 + #define IDM_SHAREDNEW 10 + #define IDM_SHAREDNEWDEFAULT 11 + #endif + #ifndef I_IMAGENONE + #define I_IMAGENONE (-2) + #endif + + #include + +#endif // !_INC_WINDOWS +#endif // RC_INVOKED + +#include "atlres.h" + +#ifdef APSTUDIO_INVOKED + #undef APSTUDIO_HIDDEN_SYMBOLS +#endif // APSTUDIO_INVOKED + +// Visual Studio dialog editor bug fix +#ifndef DS_FIXEDSYS + #define DS_FIXEDSYS 0 +#endif + +#define IDC_INFOSTATIC 0xFFFE // == IDC_STATIC -1 + +/////////////////////////////////////////////////////////////////////////////// +// Smartphone and PPC 2005 Resource IDs + +// Command and associated string resource IDs +#define ID_MENU_OK 0xE790 +#define ID_MENU_CANCEL 0xE791 +#define ID_MENU 0xE792 +#define ID_ACTION 0xE793 +#define ID_VIEW_FULLSCREEN 0xE802 + +// MenuBar resource IDs +#define ATL_IDM_MENU_DONE 0xE701 +#define ATL_IDM_MENU_CANCEL 0xE702 +#define ATL_IDM_MENU_DONECANCEL 0xE703 + +// Default device MenuBar control ID and MenuBar resource ID +#define ATL_IDW_MENU_BAR 0xE802 + +// SmartPhone spinned controls ID offset for CSpinCtrl +#define ATL_IDW_SPIN_ID 9999 + +#endif // __ATLRESCE_H__ diff --git a/wtl/wtl/include/atlscrl.h b/wtl/wtl/include/atlscrl.h new file mode 100644 index 00000000..9eb32eda --- /dev/null +++ b/wtl/wtl/include/atlscrl.h @@ -0,0 +1,2015 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLSCRL_H__ +#define __ATLSCRL_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlscrl.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlscrl.h requires atlwin.h to be included first +#endif + +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + #include +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + +#ifndef GET_WHEEL_DELTA_WPARAM + #define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) +#endif + +#ifndef WM_MOUSEHWHEEL + #define WM_MOUSEHWHEEL 0x020E +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CScrollImpl +// CScrollWindowImpl +// CMapScrollImpl +// CMapScrollWindowImpl +// CFSBWindowT +// CZoomScrollImpl +// CZoomScrollWindowImpl +// CScrollContainerImpl +// CScrollContainer + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CScrollImpl - Provides scrolling support to any window + +// Scroll extended styles +#define SCRL_SCROLLCHILDREN 0x00000001 +#define SCRL_ERASEBACKGROUND 0x00000002 +#define SCRL_NOTHUMBTRACKING 0x00000004 +#if (WINVER >= 0x0500) +#define SCRL_SMOOTHSCROLL 0x00000008 +#endif // (WINVER >= 0x0500) +#define SCRL_DISABLENOSCROLLV 0x00000010 +#define SCRL_DISABLENOSCROLLH 0x00000020 +#define SCRL_DISABLENOSCROLL (SCRL_DISABLENOSCROLLV | SCRL_DISABLENOSCROLLH) + + +template +class CScrollImpl +{ +public: + enum { uSCROLL_FLAGS = SW_INVALIDATE }; + + POINT m_ptOffset; + SIZE m_sizeAll; + SIZE m_sizeLine; + SIZE m_sizePage; + SIZE m_sizeClient; + int m_zDelta; // current wheel value + int m_nWheelLines; // number of lines to scroll on wheel +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + // Note that this message must be forwarded from a top level window + UINT m_uMsgMouseWheel; // MSH_MOUSEWHEEL +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + int m_zHDelta; // current horizontal wheel value + int m_nHWheelChars; // number of chars to scroll on horizontal wheel + UINT m_uScrollFlags; + DWORD m_dwExtendedStyle; // scroll specific extended styles + +// Constructor + CScrollImpl() : m_zDelta(0), m_nWheelLines(3), +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + m_uMsgMouseWheel(0U), +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + m_zHDelta(0), m_nHWheelChars(3), + m_uScrollFlags(0U), m_dwExtendedStyle(0) + { + m_ptOffset.x = 0; + m_ptOffset.y = 0; + m_sizeAll.cx = 0; + m_sizeAll.cy = 0; + m_sizePage.cx = 0; + m_sizePage.cy = 0; + m_sizeLine.cx = 0; + m_sizeLine.cy = 0; + m_sizeClient.cx = 0; + m_sizeClient.cy = 0; + + SetScrollExtendedStyle(SCRL_SCROLLCHILDREN | SCRL_ERASEBACKGROUND); + } + +// Attributes & Operations + DWORD GetScrollExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetScrollExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + // cache scroll flags + T* pT = static_cast(this); + pT; // avoid level 4 warning + m_uScrollFlags = pT->uSCROLL_FLAGS | (IsScrollingChildren() ? SW_SCROLLCHILDREN : 0) | (IsErasingBackground() ? SW_ERASE : 0); +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + m_uScrollFlags |= (IsSmoothScroll() ? SW_SMOOTHSCROLL : 0); +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + return dwPrevStyle; + } + + // offset operations + void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + pT->AdjustScrollOffset(x, y); + + int dx = m_ptOffset.x - x; + int dy = m_ptOffset.y - y; + m_ptOffset.x = x; + m_ptOffset.y = y; + + // block: set horizontal scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_POS; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nPos = m_ptOffset.x; + pT->SetScrollInfo(SB_HORZ, &si, bRedraw); + } + + // block: set vertical scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_POS; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nPos = m_ptOffset.y; + pT->SetScrollInfo(SB_VERT, &si, bRedraw); + } + + // Move all children if needed + if(IsScrollingChildren() && (dx != 0 || dy != 0)) + { + for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) + { + RECT rect = { 0 }; + ::GetWindowRect(hWndChild, &rect); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1); + ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + } + } + + if(bRedraw) + pT->Invalidate(); + } + + void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) + { + SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); + } + + void GetScrollOffset(POINT& ptOffset) const + { + ptOffset = m_ptOffset; + } + + // size operations + void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + m_sizeAll.cx = cx; + m_sizeAll.cy = cy; + + int x = 0; + int y = 0; + if(!bResetOffset) + { + x = m_ptOffset.x; + y = m_ptOffset.y; + pT->AdjustScrollOffset(x, y); + } + + int dx = m_ptOffset.x - x; + int dy = m_ptOffset.y - y; + m_ptOffset.x = x; + m_ptOffset.y = y; + + // block: set horizontal scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nMin = 0; + si.nMax = m_sizeAll.cx - 1; + si.nPage = m_sizeClient.cx; + si.nPos = m_ptOffset.x; + pT->SetScrollInfo(SB_HORZ, &si, bRedraw); + } + + // block: set vertical scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nMin = 0; + si.nMax = m_sizeAll.cy - 1; + si.nPage = m_sizeClient.cy; + si.nPos = m_ptOffset.y; + pT->SetScrollInfo(SB_VERT, &si, bRedraw); + } + + // Move all children if needed + if(IsScrollingChildren() && (dx != 0 || dy != 0)) + { + for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) + { + RECT rect = { 0 }; + ::GetWindowRect(hWndChild, &rect); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1); + ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + } + } + + SetScrollLine(0, 0); + SetScrollPage(0, 0); + + if(bRedraw) + pT->Invalidate(); + } + + void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(size.cx, size.cy, bRedraw, bResetOffset); + } + + void GetScrollSize(SIZE& sizeWnd) const + { + sizeWnd = m_sizeAll; + } + + // line operations + void SetScrollLine(int cxLine, int cyLine) + { + ATLASSERT(cxLine >= 0 && cyLine >= 0); + ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0); + + m_sizeLine.cx = T::CalcLineOrPage(cxLine, m_sizeAll.cx, 100); + m_sizeLine.cy = T::CalcLineOrPage(cyLine, m_sizeAll.cy, 100); + } + + void SetScrollLine(SIZE sizeLine) + { + SetScrollLine(sizeLine.cx, sizeLine.cy); + } + + void GetScrollLine(SIZE& sizeLine) const + { + sizeLine = m_sizeLine; + } + + // page operations + void SetScrollPage(int cxPage, int cyPage) + { + ATLASSERT(cxPage >= 0 && cyPage >= 0); + ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0); + + m_sizePage.cx = T::CalcLineOrPage(cxPage, m_sizeAll.cx, 10); + m_sizePage.cy = T::CalcLineOrPage(cyPage, m_sizeAll.cy, 10); + } + + void SetScrollPage(SIZE sizePage) + { + SetScrollPage(sizePage.cx, sizePage.cy); + } + + void GetScrollPage(SIZE& sizePage) const + { + sizePage = m_sizePage; + } + + // commands + void ScrollLineDown() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_LINEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollLineUp() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_LINEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollPageDown() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_PAGEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollPageUp() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_PAGEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollTop() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_TOP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollBottom() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, SB_BOTTOM, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + } + + void ScrollLineRight() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_LINEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollLineLeft() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_LINEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollPageRight() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_PAGEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollPageLeft() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_PAGEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollAllLeft() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_TOP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + void ScrollAllRight() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, SB_BOTTOM, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + } + + // scroll to make point/view/window visible + void ScrollToView(POINT pt) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + RECT rect = { pt.x, pt.y, pt.x, pt.y }; + pT->ScrollToView(rect); + } + + void ScrollToView(RECT& rect) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + RECT rcClient = { 0 }; + pT->GetClientRect(&rcClient); + + int x = m_ptOffset.x; + if(rect.left < m_ptOffset.x) + x = rect.left; + else if(rect.right > (m_ptOffset.x + rcClient.right)) + x = rect.right - rcClient.right; + + int y = m_ptOffset.y; + if(rect.top < m_ptOffset.y) + y = rect.top; + else if(rect.bottom > (m_ptOffset.y + rcClient.bottom)) + y = rect.bottom - rcClient.bottom; + + SetScrollOffset(x, y); + } + + void ScrollToView(HWND hWnd) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + RECT rect = { 0 }; + ::GetWindowRect(hWnd, &rect); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2); + ScrollToView(rect); + } + + BEGIN_MSG_MAP(CScrollImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_VSCROLL, OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + MESSAGE_HANDLER(m_uMsgMouseWheel, OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, OnSize) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + // standard scroll commands + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, OnScrollAllRight) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + GetSystemSettings(); + bHandled = FALSE; + return 1; + } + + LRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_VERT, (int)(short)LOWORD(wParam), (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + return 0; + } + + LRESULT OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + pT->DoScroll(SB_HORZ, (int)(short)LOWORD(wParam), (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + return 0; + } + + LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + +#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE) + uMsg; + int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam); +#else + int zDelta = (uMsg == WM_MOUSEWHEEL) ? (int)GET_WHEEL_DELTA_WPARAM(wParam) : (int)wParam; +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE)) + int nScrollCode = (m_nWheelLines == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGEUP : SB_PAGEDOWN) : ((zDelta > 0) ? SB_LINEUP : SB_LINEDOWN); + m_zDelta += zDelta; // cumulative + int zTotal = (m_nWheelLines == WHEEL_PAGESCROLL) ? abs(m_zDelta) : abs(m_zDelta) * m_nWheelLines; + if(m_sizeAll.cy > m_sizeClient.cy) + { + for(int i = 0; i < zTotal; i += WHEEL_DELTA) + { + pT->DoScroll(SB_VERT, nScrollCode, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); + pT->UpdateWindow(); + } + } + else // can't scroll vertically, scroll horizontally + { + for(int i = 0; i < zTotal; i += WHEEL_DELTA) + { + pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + pT->UpdateWindow(); + } + } + m_zDelta %= WHEEL_DELTA; + + return 0; + } + + LRESULT OnMouseHWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam); + int nScrollCode = (m_nHWheelChars == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGERIGHT : SB_PAGELEFT) : ((zDelta > 0) ? SB_LINERIGHT : SB_LINELEFT); + m_zHDelta += zDelta; // cumulative + int zTotal = (m_nHWheelChars == WHEEL_PAGESCROLL) ? abs(m_zHDelta) : abs(m_zHDelta) * m_nHWheelChars; + if(m_sizeAll.cx > m_sizeClient.cx) + { + for(int i = 0; i < zTotal; i += WHEEL_DELTA) + { + pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); + pT->UpdateWindow(); + } + } + m_zHDelta %= WHEEL_DELTA; + + return 0; + } + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + GetSystemSettings(); + return 0; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + m_sizeClient.cx = GET_X_LPARAM(lParam); + m_sizeClient.cy = GET_Y_LPARAM(lParam); + + // block: set horizontal scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + si.nMin = 0; + si.nMax = m_sizeAll.cx - 1; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nPage = m_sizeClient.cx; + si.nPos = m_ptOffset.x; + pT->SetScrollInfo(SB_HORZ, &si, TRUE); + } + + // block: set vertical scroll bar + { + SCROLLINFO si = { sizeof(SCROLLINFO) }; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + si.nMin = 0; + si.nMax = m_sizeAll.cy - 1; + if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) + si.fMask |= SIF_DISABLENOSCROLL; + si.nPage = m_sizeClient.cy; + si.nPos = m_ptOffset.y; + pT->SetScrollInfo(SB_VERT, &si, TRUE); + } + + int x = m_ptOffset.x; + int y = m_ptOffset.y; + if(pT->AdjustScrollOffset(x, y)) + { + // Children will be moved in SetScrollOffset, if needed + pT->ScrollWindowEx(m_ptOffset.x - x, m_ptOffset.y - y, (m_uScrollFlags & ~SCRL_SCROLLCHILDREN)); + SetScrollOffset(x, y, FALSE); + } + + bHandled = FALSE; + return 1; + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + if(wParam != NULL) + { + CDCHandle dc = (HDC)wParam; + POINT ptViewportOrg = { 0, 0 }; + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); + pT->DoPaint(dc); + dc.SetViewportOrg(ptViewportOrg); + } + else + { + CPaintDC dc(pT->m_hWnd); + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); + pT->DoPaint(dc.m_hDC); + } + return 0; + } + + // scrolling handlers + LRESULT OnScrollUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollLineUp(); + return 0; + } + + LRESULT OnScrollDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollLineDown(); + return 0; + } + + LRESULT OnScrollPageUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollPageUp(); + return 0; + } + + LRESULT OnScrollPageDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollPageDown(); + return 0; + } + + LRESULT OnScrollTop(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollTop(); + return 0; + } + + LRESULT OnScrollBottom(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollBottom(); + return 0; + } + + LRESULT OnScrollLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollLineLeft(); + return 0; + } + + LRESULT OnScrollRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollLineRight(); + return 0; + } + + LRESULT OnScrollPageLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollPageLeft(); + return 0; + } + + LRESULT OnScrollPageRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollPageRight(); + return 0; + } + + LRESULT OnScrollAllLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollAllLeft(); + return 0; + } + + LRESULT OnScrollAllRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + ScrollAllRight(); + return 0; + } + +// Overrideables + void DoPaint(CDCHandle /*dc*/) + { + // must be implemented in a derived class + ATLASSERT(FALSE); + } + +// Implementation + void DoScroll(int nType, int nScrollCode, int& cxyOffset, int cxySizeAll, int cxySizePage, int cxySizeLine) + { + T* pT = static_cast(this); + RECT rect = { 0 }; + pT->GetClientRect(&rect); + int cxyClient = (nType == SB_VERT) ? rect.bottom : rect.right; + int cxyMax = cxySizeAll - cxyClient; + + if(cxyMax < 0) // can't scroll, client area is bigger + return; + + bool bUpdate = true; + int cxyScroll = 0; + + switch(nScrollCode) + { + case SB_TOP: // top or all left + cxyScroll = cxyOffset; + cxyOffset = 0; + break; + case SB_BOTTOM: // bottom or all right + cxyScroll = cxyOffset - cxyMax; + cxyOffset = cxyMax; + break; + case SB_LINEUP: // line up or line left + if(cxyOffset >= cxySizeLine) + { + cxyScroll = cxySizeLine; + cxyOffset -= cxySizeLine; + } + else + { + cxyScroll = cxyOffset; + cxyOffset = 0; + } + break; + case SB_LINEDOWN: // line down or line right + if(cxyOffset < cxyMax - cxySizeLine) + { + cxyScroll = -cxySizeLine; + cxyOffset += cxySizeLine; + } + else + { + cxyScroll = cxyOffset - cxyMax; + cxyOffset = cxyMax; + } + break; + case SB_PAGEUP: // page up or page left + if(cxyOffset >= cxySizePage) + { + cxyScroll = cxySizePage; + cxyOffset -= cxySizePage; + } + else + { + cxyScroll = cxyOffset; + cxyOffset = 0; + } + break; + case SB_PAGEDOWN: // page down or page right + if(cxyOffset < cxyMax - cxySizePage) + { + cxyScroll = -cxySizePage; + cxyOffset += cxySizePage; + } + else + { + cxyScroll = cxyOffset - cxyMax; + cxyOffset = cxyMax; + } + break; + case SB_THUMBTRACK: + if(IsNoThumbTracking()) + break; + // else fall through + case SB_THUMBPOSITION: + { + SCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS }; + if(pT->GetScrollInfo(nType, &si)) + { + cxyScroll = cxyOffset - si.nTrackPos; + cxyOffset = si.nTrackPos; + } + } + break; + case SB_ENDSCROLL: + default: + bUpdate = false; + break; + } + + if(bUpdate && cxyScroll != 0) + { + pT->SetScrollPos(nType, cxyOffset, TRUE); + if(nType == SB_VERT) + pT->ScrollWindowEx(0, cxyScroll, m_uScrollFlags); + else + pT->ScrollWindowEx(cxyScroll, 0, m_uScrollFlags); + } + } + + static int CalcLineOrPage(int nVal, int nMax, int nDiv) + { + if(nVal == 0) + { + nVal = nMax / nDiv; + if(nVal < 1) + nVal = 1; + } + else if(nVal > nMax) + { + nVal = nMax; + } + + return nVal; + } + + bool AdjustScrollOffset(int& x, int& y) + { + int xOld = x; + int yOld = y; + + int cxMax = m_sizeAll.cx - m_sizeClient.cx; + if(x > cxMax) + x = (cxMax >= 0) ? cxMax : 0; + else if(x < 0) + x = 0; + + int cyMax = m_sizeAll.cy - m_sizeClient.cy; + if(y > cyMax) + y = (cyMax >= 0) ? cyMax : 0; + else if(y < 0) + y = 0; + + return (x != xOld || y != yOld); + } + + void GetSystemSettings() + { +#ifndef _WIN32_WCE +#ifndef SPI_GETWHEELSCROLLLINES + const UINT SPI_GETWHEELSCROLLLINES = 104; +#endif // !SPI_GETWHEELSCROLLLINES + ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &m_nWheelLines, 0); + +#ifndef SPI_GETWHEELSCROLLCHARS + const UINT SPI_GETWHEELSCROLLCHARS = 0x006C; +#endif // !SPI_GETWHEELSCROLLCHARS + ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &m_nHWheelChars, 0); + +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + if(m_uMsgMouseWheel != 0) + m_uMsgMouseWheel = ::RegisterWindowMessage(MSH_MOUSEWHEEL); + + HWND hWndWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE); + if(::IsWindow(hWndWheel)) + { + UINT uMsgScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES); + if(uMsgScrollLines != 0) + m_nWheelLines = (int)::SendMessage(hWndWheel, uMsgScrollLines, 0, 0L); + } +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) +#endif // !_WIN32_WCE + } + + bool IsScrollingChildren() const + { + return (m_dwExtendedStyle & SCRL_SCROLLCHILDREN) != 0; + } + + bool IsErasingBackground() const + { + return (m_dwExtendedStyle & SCRL_ERASEBACKGROUND) != 0; + } + + bool IsNoThumbTracking() const + { + return (m_dwExtendedStyle & SCRL_NOTHUMBTRACKING) != 0; + } + +#if (WINVER >= 0x0500) + bool IsSmoothScroll() const + { + return (m_dwExtendedStyle & SCRL_SMOOTHSCROLL) != 0; + } +#endif // (WINVER >= 0x0500) +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CScrollWindowImpl - Implements a scrollable window + +template +class ATL_NO_VTABLE CScrollWindowImpl : public ATL::CWindowImpl, public CScrollImpl< T > +{ +public: + BEGIN_MSG_MAP(CScrollWindowImpl) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, CScrollImpl< T >::OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, CScrollImpl< T >::OnPaint) +#endif // !_WIN32_WCE + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CMapScrollImpl - Provides mapping and scrolling support to any window + +#ifndef _WIN32_WCE + +template +class CMapScrollImpl : public CScrollImpl< T > +{ +public: + int m_nMapMode; + RECT m_rectLogAll; + SIZE m_sizeLogLine; + SIZE m_sizeLogPage; + +// Constructor + CMapScrollImpl() : m_nMapMode(MM_TEXT) + { + ::SetRectEmpty(&m_rectLogAll); + m_sizeLogPage.cx = 0; + m_sizeLogPage.cy = 0; + m_sizeLogLine.cx = 0; + m_sizeLogLine.cy = 0; + } + +// Attributes & Operations + // mapping mode operations + void SetScrollMapMode(int nMapMode) + { + ATLASSERT(nMapMode >= MM_MIN && nMapMode <= MM_MAX_FIXEDSCALE); + m_nMapMode = nMapMode; + } + + int GetScrollMapMode() const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + return m_nMapMode; + } + + // offset operations + void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + POINT ptOff = { x, y }; + // block: convert logical to device units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.LPtoDP(&ptOff); + } + CScrollImpl< T >::SetScrollOffset(ptOff, bRedraw); + } + + void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) + { + SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); + } + + void GetScrollOffset(POINT& ptOffset) const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + ptOffset = m_ptOffset; + // block: convert device to logical units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.DPtoLP(&ptOffset); + } + } + + // size operations + void SetScrollSize(int xMin, int yMin, int xMax, int yMax, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + ATLASSERT(xMax > xMin && yMax > yMin); + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + + ::SetRect(&m_rectLogAll, xMin, yMin, xMax, yMax); + + SIZE sizeAll = { 0 }; + sizeAll.cx = xMax - xMin + 1; + sizeAll.cy = yMax - yMin + 1; + // block: convert logical to device units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.LPtoDP(&sizeAll); + } + CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset); + SetScrollLine(0, 0); + SetScrollPage(0, 0); + } + + void SetScrollSize(RECT& rcScroll, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(rcScroll.left, rcScroll.top, rcScroll.right, rcScroll.bottom, bRedraw, bResetOffset); + } + + void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(0, 0, cx, cy, bRedraw, bResetOffset); + } + + void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(0, 0, size.cx, size.cy, bRedraw, bResetOffset); + } + + void GetScrollSize(RECT& rcScroll) const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + rcScroll = m_rectLogAll; + } + + // line operations + void SetScrollLine(int cxLine, int cyLine) + { + ATLASSERT(cxLine >= 0 && cyLine >= 0); + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + + m_sizeLogLine.cx = cxLine; + m_sizeLogLine.cy = cyLine; + SIZE sizeLine = m_sizeLogLine; + // block: convert logical to device units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.LPtoDP(&sizeLine); + } + CScrollImpl< T >::SetScrollLine(sizeLine); + } + + void SetScrollLine(SIZE sizeLine) + { + SetScrollLine(sizeLine.cx, sizeLine.cy); + } + + void GetScrollLine(SIZE& sizeLine) const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + sizeLine = m_sizeLogLine; + } + + // page operations + void SetScrollPage(int cxPage, int cyPage) + { + ATLASSERT(cxPage >= 0 && cyPage >= 0); + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + + m_sizeLogPage.cx = cxPage; + m_sizeLogPage.cy = cyPage; + SIZE sizePage = m_sizeLogPage; + // block: convert logical to device units + { + CWindowDC dc(NULL); + dc.SetMapMode(m_nMapMode); + dc.LPtoDP(&sizePage); + } + CScrollImpl< T >::SetScrollPage(sizePage); + } + + void SetScrollPage(SIZE sizePage) + { + SetScrollPage(sizePage.cx, sizePage.cy); + } + + void GetScrollPage(SIZE& sizePage) const + { + ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); + sizePage = m_sizeLogPage; + } + + BEGIN_MSG_MAP(CMapScrollImpl) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + if(wParam != NULL) + { + CDCHandle dc = (HDC)wParam; + int nMapModeSav = dc.GetMapMode(); + dc.SetMapMode(m_nMapMode); + POINT ptViewportOrg = { 0, 0 }; + if(m_nMapMode == MM_TEXT) + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); + else + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy, &ptViewportOrg); + POINT ptWindowOrg = { 0, 0 }; + dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top, &ptWindowOrg); + + pT->DoPaint(dc); + + dc.SetMapMode(nMapModeSav); + dc.SetViewportOrg(ptViewportOrg); + dc.SetWindowOrg(ptWindowOrg); + } + else + { + CPaintDC dc(pT->m_hWnd); + dc.SetMapMode(m_nMapMode); + if(m_nMapMode == MM_TEXT) + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); + else + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy); + dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top); + pT->DoPaint(dc.m_hDC); + } + return 0; + } +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CMapScrollWindowImpl - Implements scrolling window with mapping + +#ifndef _WIN32_WCE + +template +class ATL_NO_VTABLE CMapScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CMapScrollImpl< T > +{ +public: + BEGIN_MSG_MAP(CMapScrollWindowImpl) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, CMapScrollImpl< T >::OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, CMapScrollImpl< T >::OnPaint) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CFSBWindow - Use as a base instead of CWindow to get flat scroll bar support + +#if defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + +template +class CFSBWindowT : public TBase, public CFlatScrollBarImpl > +{ +public: +// Constructors + CFSBWindowT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CFSBWindowT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + +// CWindow overrides that use flat scroll bar API +// (only those methods that are used by scroll window classes) + int SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return FlatSB_SetScrollPos(nBar, nPos, bRedraw); + } + + BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + return FlatSB_GetScrollInfo(nBar, lpScrollInfo); + } + + BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + return FlatSB_SetScrollInfo(nBar, lpScrollInfo, bRedraw); + } +}; + +typedef CFSBWindowT CFSBWindow; + +#endif // defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) + + +/////////////////////////////////////////////////////////////////////////////// +// CZoomScrollImpl - Provides zooming and scrolling support to any window + +#ifndef _WIN32_WCE + +// The zoom modes that can be set with the SetZoomMode method +enum +{ + ZOOMMODE_OFF, + ZOOMMODE_IN, // If left mouse button is clicked or dragged, zoom in on point clicked or rectangle dragged. + ZOOMMODE_OUT // If left mouse button clicked, zoom out on point clicked. +}; + +// Notification to parent that zoom scale changed as a result of user mouse action. +#define ZSN_ZOOMCHANGED (NM_FIRST - 50) + +template +class CZoomScrollImpl : public CScrollImpl< T > +{ +public: + enum { m_cxyMinZoomRect = 12 }; // min rect size to zoom in on rect. + +// Data members + SIZE m_sizeLogAll; + SIZE m_sizeLogLine; + SIZE m_sizeLogPage; + float m_fZoomScale; + float m_fZoomScaleMin; + float m_fZoomDelta; // Used in ZOOMMODE_IN and ZOOMMODE_OUT on left-button click. + int m_nZoomMode; + RECT m_rcTrack; + bool m_bTracking; + +// Constructor + CZoomScrollImpl(): + m_fZoomScale(1.0), + m_fZoomScaleMin(0.5), + m_fZoomDelta(0.5), + m_nZoomMode(ZOOMMODE_OFF), + m_bTracking(false) + { + m_sizeLogAll.cx = 0; + m_sizeLogAll.cy = 0; + m_sizeLogPage.cx = 0; + m_sizeLogPage.cy = 0; + m_sizeLogLine.cx = 0; + m_sizeLogLine.cy = 0; + ::SetRectEmpty(&m_rcTrack); + } + +// Attributes & Operations + + // size operations + void SetScrollSize(int cxLog, int cyLog, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + ATLASSERT(cxLog >= 0 && cyLog >= 0); + + // Set up the defaults + if (cxLog == 0 && cyLog == 0) + { + cxLog = 1; + cyLog = 1; + } + + m_sizeLogAll.cx = cxLog; + m_sizeLogAll.cy = cyLog; + SIZE sizeAll = { 0 }; + sizeAll.cx = (int)((float)m_sizeLogAll.cx * m_fZoomScale); + sizeAll.cy = (int)((float)m_sizeLogAll.cy * m_fZoomScale); + + CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset); + } + + void SetScrollSize(SIZE sizeLog, BOOL bRedraw = TRUE, bool bResetOffset = true) + { + SetScrollSize(sizeLog.cx, sizeLog.cy, bRedraw, bResetOffset); + } + + void GetScrollSize(SIZE& sizeLog) const + { + sizeLog = m_sizeLogAll; + } + + // line operations + void SetScrollLine(int cxLogLine, int cyLogLine) + { + ATLASSERT(cxLogLine >= 0 && cyLogLine >= 0); + + m_sizeLogLine.cx = cxLogLine; + m_sizeLogLine.cy = cyLogLine; + + SIZE sizeLine = { 0 }; + sizeLine.cx = (int)((float)m_sizeLogLine.cx * m_fZoomScale); + sizeLine.cy = (int)((float)m_sizeLogLine.cy * m_fZoomScale); + CScrollImpl< T >::SetScrollLine(sizeLine); + } + + void SetScrollLine(SIZE sizeLogLine) + { + SetScrollLine(sizeLogLine.cx, sizeLogLine.cy); + } + + void GetScrollLine(SIZE& sizeLogLine) const + { + sizeLogLine = m_sizeLogLine; + } + + // page operations + void SetScrollPage(int cxLogPage, int cyLogPage) + { + ATLASSERT(cxLogPage >= 0 && cyLogPage >= 0); + + m_sizeLogPage.cx = cxLogPage; + m_sizeLogPage.cy = cyLogPage; + + SIZE sizePage = { 0 }; + sizePage.cx = (int)((float)m_sizeLogPage.cx * m_fZoomScale); + sizePage.cy = (int)((float)m_sizeLogPage.cy * m_fZoomScale); + + CScrollImpl< T >::SetScrollPage(sizePage); + } + + void SetScrollPage(SIZE sizeLogPage) + { + SetScrollPage(sizeLogPage.cx, sizeLogPage.cy); + } + + void GetScrollPage(SIZE& sizeLogPage) const + { + sizeLogPage = m_sizeLogPage; + } + + void SetZoomScale(float fZoomScale) + { + ATLASSERT(fZoomScale > 0); + + if(fZoomScale > 0 && fZoomScale >= m_fZoomScaleMin) + m_fZoomScale = fZoomScale; + } + + float GetZoomScale() const + { + return m_fZoomScale; + } + + void SetZoomScaleMin(float fZoomScaleMin) + { + m_fZoomScaleMin = fZoomScaleMin; + } + + float GetZoomScaleMin() const + { + return m_fZoomScaleMin; + } + + void SetZoomDelta(float fZoomDelta) + { + ATLASSERT(fZoomDelta >= 0); + + if(fZoomDelta >= 0) + m_fZoomDelta = fZoomDelta; + } + + float GetZoomDelta() const + { + return m_fZoomDelta; + } + + void SetZoomMode(int nZoomMode) + { + m_nZoomMode = nZoomMode; + } + + int GetZoomMode() const + { + return m_nZoomMode; + } + + void Zoom(int x, int y, float fZoomScale) + { + if(fZoomScale <= 0) + return; + + fZoomScale = max(fZoomScale, m_fZoomScaleMin); + + T* pT = static_cast(this); + POINT pt = { x, y }; + if(!pT->PtInDevRect(pt)) + return; + + pT->ViewDPtoLP(&pt); + pT->Zoom(fZoomScale, false); + pT->CenterOnLogicalPoint(pt); + } + + void Zoom(POINT pt, float fZoomScale) + { + T* pT = static_cast(this); + pT->Zoom(pt.x, pt.y, fZoomScale); + } + + void Zoom(RECT& rc) + { + T* pT = static_cast(this); + RECT rcZoom = rc; + pT->NormalizeRect(rcZoom); + SIZE size = { rcZoom.right - rcZoom.left, rcZoom.bottom - rcZoom.top }; + POINT pt = { rcZoom.left + size.cx / 2, rcZoom.top + size.cy / 2 }; + if(size.cx < m_cxyMinZoomRect || size.cy < m_cxyMinZoomRect) + { + pT->Zoom(pt, m_fZoomScale + m_fZoomDelta); + return; + } + + ATLASSERT(size.cx > 0 && size.cy > 0); + + float fScaleH = (float)(m_sizeClient.cx + 1) / (float)size.cx; + float fScaleV = (float)(m_sizeClient.cy + 1) / (float)size.cy; + float fZoomScale = min(fScaleH, fScaleV) * m_fZoomScale; + pT->Zoom(pt, fZoomScale); + } + + void Zoom(float fZoomScale, bool bCenter = true) + { + if(fZoomScale <= 0) + return; + + fZoomScale = max(fZoomScale, m_fZoomScaleMin); + + + T* pT = static_cast(this); + POINT pt = { 0 }; + if(bCenter) + { + RECT rc; + ::GetClientRect(pT->m_hWnd, &rc); + pt.x = rc.right / 2; + pt.y = rc.bottom / 2; + pT->ViewDPtoLP(&pt); + } + + // Modify the Viewport extent + m_fZoomScale = fZoomScale; + SIZE sizeAll = { 0 }; + sizeAll.cx = (int)((float)m_sizeLogAll.cx * fZoomScale); + sizeAll.cy = (int)((float)m_sizeLogAll.cy * fZoomScale); + + // Update scroll bars and window + CScrollImpl< T >::SetScrollSize(sizeAll); + + if(bCenter) + pT->CenterOnLogicalPoint(pt); + } + + // Helper functions + void PrepareDC(CDCHandle dc) + { + ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0); + dc.SetMapMode(MM_ANISOTROPIC); + dc.SetWindowExt(m_sizeLogAll); + dc.SetViewportExt(m_sizeAll); + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); + } + + void ViewDPtoLP(LPPOINT lpPoints, int nCount = 1) + { + ATLASSERT(lpPoints); + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + CWindowDC dc(pT->m_hWnd); + pT->PrepareDC(dc.m_hDC); + dc.DPtoLP(lpPoints, nCount); + } + + void ViewLPtoDP(LPPOINT lpPoints, int nCount = 1) + { + ATLASSERT(lpPoints); + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + + CWindowDC dc(pT->m_hWnd); + pT->PrepareDC(dc.m_hDC); + dc.LPtoDP(lpPoints, nCount); + } + + void ClientToDevice(POINT &pt) + { + pt.x += m_ptOffset.x; + pt.y += m_ptOffset.y; + } + + void DeviceToClient(POINT &pt) + { + pt.x -= m_ptOffset.x; + pt.y -= m_ptOffset.y; + } + + void CenterOnPoint(POINT pt) + { + T* pT = static_cast(this); + RECT rect; + pT->GetClientRect(&rect); + + int xOfs = pt.x - (rect.right / 2) + m_ptOffset.x; + if(xOfs < 0) + { + xOfs = 0; + } + else + { + int xMax = max((int)(m_sizeAll.cx - rect.right), 0); + if(xOfs > xMax) + xOfs = xMax; + } + + int yOfs = pt.y - (rect.bottom / 2) + m_ptOffset.y; + if(yOfs < 0) + { + yOfs = 0; + } + else + { + int yMax = max((int)(m_sizeAll.cy - rect.bottom), 0); + if(yOfs > yMax) + yOfs = yMax; + } + + CScrollImpl< T >::SetScrollOffset(xOfs, yOfs); + } + + void CenterOnLogicalPoint(POINT ptLog) + { + T* pT = static_cast(this); + pT->ViewLPtoDP(&ptLog); + pT->DeviceToClient(ptLog); + pT->CenterOnPoint(ptLog); + } + + BOOL PtInDevRect(POINT pt) + { + RECT rc = { 0, 0, m_sizeAll.cx, m_sizeAll.cy }; + ::OffsetRect(&rc, -m_ptOffset.x, -m_ptOffset.y); + return ::PtInRect(&rc, pt); + } + + void NormalizeRect(RECT& rc) + { + if(rc.left > rc.right) + { + int r = rc.right; + rc.right = rc.left; + rc.left = r; + } + if(rc.top > rc.bottom) + { + int b = rc.bottom; + rc.bottom = rc.top; + rc.top = b; + } + } + + void DrawTrackRect() + { + T* pT = static_cast(this); + const SIZE sizeLines = { 2, 2 }; + RECT rc = m_rcTrack; + pT->NormalizeRect(rc); + if(!::IsRectEmpty(&rc)) + { + ::MapWindowPoints(pT->m_hWnd, NULL, (LPPOINT)&rc, 2); + CWindowDC dc(NULL); + dc.DrawDragRect(&rc, sizeLines, NULL, sizeLines); + } + } + + void NotifyParentZoomChanged() + { + T* pT = static_cast(this); + int nId = pT->GetDlgCtrlID(); + NMHDR nmhdr = { pT->m_hWnd, nId, ZSN_ZOOMCHANGED }; + ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nId, (LPARAM)&nmhdr); + } + + BEGIN_MSG_MAP(CZoomScrollImpl) + MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATLASSERT(m_sizeLogAll.cx >= 0 && m_sizeLogAll.cy >= 0); + ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0); + + if(wParam != NULL) + { + CDCHandle dc = (HDC)wParam; + int nMapModeSav = dc.GetMapMode(); + dc.SetMapMode(MM_ANISOTROPIC); + SIZE szWindowExt = { 0, 0 }; + dc.SetWindowExt(m_sizeLogAll, &szWindowExt); + SIZE szViewportExt = { 0, 0 }; + dc.SetViewportExt(m_sizeAll, &szViewportExt); + POINT ptViewportOrg = { 0, 0 }; + dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); + + pT->DoPaint(dc); + + dc.SetMapMode(nMapModeSav); + dc.SetWindowExt(szWindowExt); + dc.SetViewportExt(szViewportExt); + dc.SetViewportOrg(ptViewportOrg); + } + else + { + CPaintDC dc(pT->m_hWnd); + pT->PrepareDC(dc.m_hDC); + pT->DoPaint(dc.m_hDC); + } + return 0; + } + + LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(m_nZoomMode == ZOOMMODE_IN && !m_bTracking) + { + T* pT = static_cast(this); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if(pT->PtInDevRect(pt)) + { + pT->SetCapture(); + m_bTracking = true; + ::SetRect(&m_rcTrack, pt.x, pt.y, pt.x, pt.y); + } + } + bHandled = FALSE; + return 0; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + if(m_bTracking) + { + T* pT = static_cast(this); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + if(pT->PtInDevRect(pt)) + { + pT->DrawTrackRect(); + m_rcTrack.right = pt.x; + m_rcTrack.bottom = pt.y; + pT->DrawTrackRect(); + } + } + bHandled = FALSE; + return 0; + } + + LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + ::ReleaseCapture(); + if(m_nZoomMode == ZOOMMODE_OUT) + { + T* pT = static_cast(this); + pT->Zoom(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_fZoomScale - m_fZoomDelta); + pT->NotifyParentZoomChanged(); + } + bHandled = FALSE; + return 0; + } + + LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_bTracking) + { + m_bTracking = false; + T* pT = static_cast(this); + pT->DrawTrackRect(); + pT->Zoom(m_rcTrack); + pT->NotifyParentZoomChanged(); + ::SetRectEmpty(&m_rcTrack); + } + bHandled = FALSE; + return 0; + } + + LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if(LOWORD(lParam) == HTCLIENT && m_nZoomMode != ZOOMMODE_OFF) + { + T* pT = static_cast(this); + if((HWND)wParam == pT->m_hWnd) + { + DWORD dwPos = ::GetMessagePos(); + POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; + pT->ScreenToClient(&pt); + if(pT->PtInDevRect(pt)) + { + ::SetCursor(::LoadCursor(NULL, IDC_CROSS)); + return 1; + } + } + } + bHandled = FALSE; + return 0; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CZoomScrollWindowImpl - Implements scrolling window with zooming + +template +class ATL_NO_VTABLE CZoomScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T > +{ +public: + BEGIN_MSG_MAP(CZoomScrollWindowImpl) + MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor) + MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) + MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) + MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) +#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) +#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) + MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) + MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) + MESSAGE_HANDLER(WM_PAINT, CZoomScrollImpl< T >::OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, CZoomScrollImpl< T >::OnPaint) + MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown) + MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp) + MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged) + ALT_MSG_MAP(1) + COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) + COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) + COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) + COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) + COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) + COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) + COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) + COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) + END_MSG_MAP() +}; + +#endif // !_WIN32_WCE + + +/////////////////////////////////////////////////////////////////////////////// +// CScrollContainer + +template +class ATL_NO_VTABLE CScrollContainerImpl : public CScrollWindowImpl< T, TBase, TWinTraits > +{ +public: + DECLARE_WND_CLASS_EX(NULL, 0, -1) + + typedef CScrollWindowImpl< T, TBase, TWinTraits > _baseClass; + +// Data members + ATL::CWindow m_wndClient; + bool m_bAutoSizeClient; + bool m_bDrawEdgeIfEmpty; + +// Constructor + CScrollContainerImpl() : m_bAutoSizeClient(true), m_bDrawEdgeIfEmpty(false) + { + // Set CScrollWindowImpl extended style + SetScrollExtendedStyle(SCRL_SCROLLCHILDREN); + } + +// Attributes + HWND GetClient() const + { + return m_wndClient; + } + + HWND SetClient(HWND hWndClient, bool bClientSizeAsMin = true) + { + ATLASSERT(::IsWindow(m_hWnd)); + + HWND hWndOldClient = m_wndClient; + m_wndClient = hWndClient; + + SetRedraw(FALSE); + SetScrollSize(1, 1, FALSE); + + if(m_wndClient.m_hWnd != NULL) + { + m_wndClient.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE); + + if(bClientSizeAsMin) + { + RECT rect = { 0 }; + m_wndClient.GetWindowRect(&rect); + if((rect.right - rect.left) > 0 && (rect.bottom - rect.top) > 0) + SetScrollSize(rect.right - rect.left, rect.bottom - rect.top, FALSE); + } + + T* pT = static_cast(this); + pT->UpdateLayout(); + } + + SetRedraw(TRUE); + RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN); + + return hWndOldClient; + } + +// Message map and handlers + BEGIN_MSG_MAP(CScrollContainerImpl) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_SIZE, OnSize) + CHAIN_MSG_MAP(_baseClass) + FORWARD_NOTIFICATIONS() + ALT_MSG_MAP(1) + CHAIN_MSG_MAP_ALT(_baseClass, 1) + END_MSG_MAP() + + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(m_wndClient.m_hWnd != NULL) + m_wndClient.SetFocus(); + + return 0; + } + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background needed + } + + LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + BOOL bTmp = TRUE; + LRESULT lRet = _baseClass::OnSize(uMsg, wParam, lParam, bTmp); + + T* pT = static_cast(this); + pT->UpdateLayout(); + + return lRet; + } + +// Overrides for CScrollWindowImpl + void DoPaint(CDCHandle dc) + { + if(!m_bAutoSizeClient || m_wndClient.m_hWnd == NULL) + { + T* pT = static_cast(this); + RECT rect = { 0 }; + pT->GetContainerRect(rect); + + if(m_bDrawEdgeIfEmpty && m_wndClient.m_hWnd == NULL) + dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + + dc.FillRect(&rect, COLOR_APPWORKSPACE); + } + } + + void ScrollToView(POINT pt) + { + CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(pt); + } + + void ScrollToView(RECT& rect) + { + CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(rect); + } + + void ScrollToView(HWND hWnd) // client window coordinates + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATLASSERT(m_wndClient.IsWindow()); + + RECT rect = { 0 }; + ::GetWindowRect(hWnd, &rect); + ::MapWindowPoints(NULL, m_wndClient.m_hWnd, (LPPOINT)&rect, 2); + ScrollToView(rect); + } + +// Implementation - overrideable methods + void UpdateLayout() + { + ATLASSERT(::IsWindow(m_hWnd)); + + if(m_bAutoSizeClient && m_wndClient.m_hWnd != NULL) + { + T* pT = static_cast(this); + RECT rect = { 0 }; + pT->GetContainerRect(rect); + + m_wndClient.SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE); + } + else + { + Invalidate(); + } + } + + void GetContainerRect(RECT& rect) + { + GetClientRect(&rect); + + if(rect.right < m_sizeAll.cx) + rect.right = m_sizeAll.cx; + + if(rect.bottom < m_sizeAll.cy) + rect.bottom = m_sizeAll.cy; + } +}; + +class CScrollContainer : public CScrollContainerImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_ScrollContainer"), 0, -1) +}; + +}; // namespace WTL + +#endif // __ATLSCRL_H__ diff --git a/wtl/wtl/include/atlsplit.h b/wtl/wtl/include/atlsplit.h new file mode 100644 index 00000000..df879dbc --- /dev/null +++ b/wtl/wtl/include/atlsplit.h @@ -0,0 +1,892 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLSPLIT_H__ +#define __ATLSPLIT_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlsplit.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlsplit.h requires atlwin.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CSplitterImpl +// CSplitterWindowImpl +// CSplitterWindowT + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CSplitterImpl - Provides splitter support to any window + +// Splitter panes constants +#define SPLIT_PANE_LEFT 0 +#define SPLIT_PANE_RIGHT 1 +#define SPLIT_PANE_TOP SPLIT_PANE_LEFT +#define SPLIT_PANE_BOTTOM SPLIT_PANE_RIGHT +#define SPLIT_PANE_NONE -1 + +// Splitter extended styles +#define SPLIT_PROPORTIONAL 0x00000001 +#define SPLIT_NONINTERACTIVE 0x00000002 +#define SPLIT_RIGHTALIGNED 0x00000004 +#define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED + +// Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are +// mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL + + +template +class CSplitterImpl +{ +public: + enum { m_nPanesCount = 2, m_nPropMax = 10000 }; + + HWND m_hWndPane[m_nPanesCount]; + RECT m_rcSplitter; + int m_xySplitterPos; + int m_nDefActivePane; + int m_cxySplitBar; // splitter bar width/height + static HCURSOR m_hCursor; + int m_cxyMin; // minimum pane size + int m_cxyBarEdge; // splitter bar edge + bool m_bFullDrag; + int m_cxyDragOffset; + int m_nProportionalPos; + bool m_bUpdateProportionalPos; + DWORD m_dwExtendedStyle; // splitter specific extended styles + int m_nSinglePane; // single pane mode + +// Constructor + CSplitterImpl() : + m_xySplitterPos(-1), m_nDefActivePane(SPLIT_PANE_NONE), + m_cxySplitBar(0), m_cxyMin(0), m_cxyBarEdge(0), m_bFullDrag(true), + m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true), + m_dwExtendedStyle(SPLIT_PROPORTIONAL), + m_nSinglePane(SPLIT_PANE_NONE) + { + m_hWndPane[SPLIT_PANE_LEFT] = NULL; + m_hWndPane[SPLIT_PANE_RIGHT] = NULL; + + ::SetRectEmpty(&m_rcSplitter); + + if(m_hCursor == NULL) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CSplitterImpl::CSplitterImpl.\n")); + ATLASSERT(FALSE); + return; + } + + if(m_hCursor == NULL) + m_hCursor = ::LoadCursor(NULL, t_bVertical ? IDC_SIZEWE : IDC_SIZENS); + + lock.Unlock(); + } + } + +// Attributes + void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true) + { + if(lpRect == NULL) + { + T* pT = static_cast(this); + pT->GetClientRect(&m_rcSplitter); + } + else + { + m_rcSplitter = *lpRect; + } + + if(IsProportional()) + UpdateProportionalPos(); + else if(IsRightAligned()) + UpdateRightAlignPos(); + + if(bUpdate) + UpdateSplitterLayout(); + } + + void GetSplitterRect(LPRECT lpRect) const + { + ATLASSERT(lpRect != NULL); + *lpRect = m_rcSplitter; + } + + bool SetSplitterPos(int xyPos = -1, bool bUpdate = true) + { + if(xyPos == -1) // -1 == middle + { + if(t_bVertical) + xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2; + else + xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2; + } + + // Adjust if out of valid range + int cxyMax = 0; + if(t_bVertical) + cxyMax = m_rcSplitter.right - m_rcSplitter.left; + else + cxyMax = m_rcSplitter.bottom - m_rcSplitter.top; + + if(xyPos < m_cxyMin + m_cxyBarEdge) + xyPos = m_cxyMin; + else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin)) + xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin; + + // Set new position and update if requested + bool bRet = (m_xySplitterPos != xyPos); + m_xySplitterPos = xyPos; + + if(m_bUpdateProportionalPos) + { + if(IsProportional()) + StoreProportionalPos(); + else if(IsRightAligned()) + StoreRightAlignPos(); + } + else + { + m_bUpdateProportionalPos = true; + } + + if(bUpdate && bRet) + UpdateSplitterLayout(); + + return bRet; + } + + void SetSplitterPosPct(int nPct, bool bUpdate = true) + { + ATLASSERT(nPct >= 0 && nPct <= 100); + + m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100); + UpdateProportionalPos(); + + if(bUpdate) + UpdateSplitterLayout(); + } + + int GetSplitterPos() const + { + return m_xySplitterPos; + } + + bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE) + { + ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE); + if(!(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT || nPane == SPLIT_PANE_NONE)) + return false; + + if(nPane != SPLIT_PANE_NONE) + { + if(!::IsWindowVisible(m_hWndPane[nPane])) + ::ShowWindow(m_hWndPane[nPane], SW_SHOW); + int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT; + ::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE); + if(m_nDefActivePane != nPane) + m_nDefActivePane = nPane; + } + else if(m_nSinglePane != SPLIT_PANE_NONE) + { + int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT; + ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW); + } + + m_nSinglePane = nPane; + UpdateSplitterLayout(); + return true; + } + + int GetSinglePaneMode() const + { + return m_nSinglePane; + } + + DWORD GetSplitterExtendedStyle() const + { + return m_dwExtendedStyle; + } + + DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); +#ifdef _DEBUG + if(IsProportional() && IsRightAligned()) + ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n")); +#endif // _DEBUG + return dwPrevStyle; + } + +// Splitter operations + void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true) + { + m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop; + m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom; + ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]); + if(bUpdate) + UpdateSplitterLayout(); + } + + bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true) + { + ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); + + if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) + return false; + m_hWndPane[nPane] = hWnd; + ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]); + if(bUpdate) + UpdateSplitterLayout(); + return true; + } + + HWND GetSplitterPane(int nPane) const + { + ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); + + if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) + return false; + return m_hWndPane[nPane]; + } + + bool SetActivePane(int nPane) + { + ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); + + if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) + return false; + if(m_nSinglePane != SPLIT_PANE_NONE && nPane != m_nSinglePane) + return false; + ::SetFocus(m_hWndPane[nPane]); + m_nDefActivePane = nPane; + return true; + } + + int GetActivePane() const + { + int nRet = SPLIT_PANE_NONE; + HWND hWndFocus = ::GetFocus(); + if(hWndFocus != NULL) + { + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if(hWndFocus == m_hWndPane[nPane] || ::IsChild(m_hWndPane[nPane], hWndFocus)) + { + nRet = nPane; + break; + } + } + } + return nRet; + } + + bool ActivateNextPane(bool bNext = true) + { + int nPane = m_nSinglePane; + if(nPane == SPLIT_PANE_NONE) + { + switch(GetActivePane()) + { + case SPLIT_PANE_LEFT: + nPane = SPLIT_PANE_RIGHT; + break; + case SPLIT_PANE_RIGHT: + nPane = SPLIT_PANE_LEFT; + break; + default: + nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT; + break; + } + } + return SetActivePane(nPane); + } + + bool SetDefaultActivePane(int nPane) + { + ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); + + if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT) + return false; + m_nDefActivePane = nPane; + return true; + } + + bool SetDefaultActivePane(HWND hWnd) + { + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if(hWnd == m_hWndPane[nPane]) + { + m_nDefActivePane = nPane; + return true; + } + } + return false; // not found + } + + int GetDefaultActivePane() const + { + return m_nDefActivePane; + } + + void DrawSplitter(CDCHandle dc) + { + ATLASSERT(dc.m_hDC != NULL); + if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) + return; + + T* pT = static_cast(this); + if(m_nSinglePane == SPLIT_PANE_NONE) + { + pT->DrawSplitterBar(dc); + + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if(m_hWndPane[nPane] == NULL) + pT->DrawSplitterPane(dc, nPane); + } + } + else + { + if(m_hWndPane[m_nSinglePane] == NULL) + pT->DrawSplitterPane(dc, m_nSinglePane); + } + } + +// Overrideables + void DrawSplitterBar(CDCHandle dc) + { + RECT rect; + if(GetSplitterBarRect(&rect)) + { + dc.FillRect(&rect, COLOR_3DFACE); + // draw 3D edge if needed + T* pT = static_cast(this); + if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0) + dc.DrawEdge(&rect, EDGE_RAISED, t_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM)); + } + } + + // called only if pane is empty + void DrawSplitterPane(CDCHandle dc, int nPane) + { + RECT rect; + if(GetSplitterPaneRect(nPane, &rect)) + { + T* pT = static_cast(this); + if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0) + dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + dc.FillRect(&rect, COLOR_APPWORKSPACE); + } + } + +// Message map and handlers + BEGIN_MSG_MAP(CSplitterImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_PAINT, OnPaint) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) +#endif // !_WIN32_WCE + if(IsInteractive()) + { + MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) + MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) + MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick) + MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) + } + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) +#ifndef _WIN32_WCE + MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) +#endif // !_WIN32_WCE + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + GetSystemSettings(false); + bHandled = FALSE; + return 1; + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + // try setting position if not set + if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) + pT->SetSplitterPos(); + // do painting + CPaintDC dc(pT->m_hWnd); + pT->DrawSplitter(dc.m_hDC); + return 0; + } + + LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + if((HWND)wParam == pT->m_hWnd && LOWORD(lParam) == HTCLIENT) + { + DWORD dwPos = ::GetMessagePos(); + POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; + pT->ScreenToClient(&ptPos); + if(IsOverSplitterBar(ptPos.x, ptPos.y)) + return 1; + } + + bHandled = FALSE; + return 0; + } + + LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + int xPos = GET_X_LPARAM(lParam); + int yPos = GET_Y_LPARAM(lParam); + if((wParam & MK_LBUTTON) && ::GetCapture() == pT->m_hWnd) + { + int xyNewSplitPos = 0; + if(t_bVertical) + xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset; + else + xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset; + + if(xyNewSplitPos == -1) // avoid -1, that means middle + xyNewSplitPos = -2; + + if(m_xySplitterPos != xyNewSplitPos) + { + if(m_bFullDrag) + { + if(pT->SetSplitterPos(xyNewSplitPos, true)) + pT->UpdateWindow(); + } + else + { + DrawGhostBar(); + pT->SetSplitterPos(xyNewSplitPos, false); + DrawGhostBar(); + } + } + } + else // not dragging, just set cursor + { + if(IsOverSplitterBar(xPos, yPos)) + ::SetCursor(m_hCursor); + bHandled = FALSE; + } + + return 0; + } + + LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + int xPos = GET_X_LPARAM(lParam); + int yPos = GET_Y_LPARAM(lParam); + if(IsOverSplitterBar(xPos, yPos)) + { + T* pT = static_cast(this); + pT->SetCapture(); + ::SetCursor(m_hCursor); + if(!m_bFullDrag) + DrawGhostBar(); + if(t_bVertical) + m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos; + else + m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos; + } + bHandled = FALSE; + return 1; + } + + LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + ::ReleaseCapture(); + bHandled = FALSE; + return 1; + } + + LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->SetSplitterPos(); // middle + return 0; + } + + LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + if(!m_bFullDrag) + { + DrawGhostBar(); + UpdateSplitterLayout(); + T* pT = static_cast(this); + pT->UpdateWindow(); + } + return 0; + } + + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled) + { + if(m_nSinglePane == SPLIT_PANE_NONE) + { + if(m_nDefActivePane == SPLIT_PANE_LEFT || m_nDefActivePane == SPLIT_PANE_RIGHT) + ::SetFocus(m_hWndPane[m_nDefActivePane]); + } + else + { + ::SetFocus(m_hWndPane[m_nSinglePane]); + } + bHandled = FALSE; + return 1; + } + +#ifndef _WIN32_WCE + LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); + if(lRet == MA_ACTIVATE || lRet == MA_ACTIVATEANDEAT) + { + DWORD dwPos = ::GetMessagePos(); + POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; + pT->ScreenToClient(&pt); + RECT rcPane; + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if(GetSplitterPaneRect(nPane, &rcPane) && ::PtInRect(&rcPane, pt)) + { + m_nDefActivePane = nPane; + break; + } + } + } + return lRet; + } +#endif // !_WIN32_WCE + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + GetSystemSettings(true); + return 0; + } + +// Implementation - internal helpers + void UpdateSplitterLayout() + { + if(m_nSinglePane == SPLIT_PANE_NONE && m_xySplitterPos == -1) + return; + + T* pT = static_cast(this); + RECT rect = { 0, 0, 0, 0 }; + if(m_nSinglePane == SPLIT_PANE_NONE) + { + if(GetSplitterBarRect(&rect)) + pT->InvalidateRect(&rect); + + for(int nPane = 0; nPane < m_nPanesCount; nPane++) + { + if(GetSplitterPaneRect(nPane, &rect)) + { + if(m_hWndPane[nPane] != NULL) + ::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); + else + pT->InvalidateRect(&rect); + } + } + } + else + { + if(GetSplitterPaneRect(m_nSinglePane, &rect)) + { + if(m_hWndPane[m_nSinglePane] != NULL) + ::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); + else + pT->InvalidateRect(&rect); + } + } + } + + bool GetSplitterBarRect(LPRECT lpRect) const + { + ATLASSERT(lpRect != NULL); + if(m_nSinglePane != SPLIT_PANE_NONE || m_xySplitterPos == -1) + return false; + + if(t_bVertical) + { + lpRect->left = m_rcSplitter.left + m_xySplitterPos; + lpRect->top = m_rcSplitter.top; + lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; + lpRect->bottom = m_rcSplitter.bottom; + } + else + { + lpRect->left = m_rcSplitter.left; + lpRect->top = m_rcSplitter.top + m_xySplitterPos; + lpRect->right = m_rcSplitter.right; + lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; + } + + return true; + } + + bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const + { + ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT); + ATLASSERT(lpRect != NULL); + bool bRet = true; + if(m_nSinglePane != SPLIT_PANE_NONE) + { + if(nPane == m_nSinglePane) + *lpRect = m_rcSplitter; + else + bRet = false; + } + else if(nPane == SPLIT_PANE_LEFT) + { + if(t_bVertical) + { + lpRect->left = m_rcSplitter.left; + lpRect->top = m_rcSplitter.top; + lpRect->right = m_rcSplitter.left + m_xySplitterPos; + lpRect->bottom = m_rcSplitter.bottom; + } + else + { + lpRect->left = m_rcSplitter.left; + lpRect->top = m_rcSplitter.top; + lpRect->right = m_rcSplitter.right; + lpRect->bottom = m_rcSplitter.top + m_xySplitterPos; + } + } + else if(nPane == SPLIT_PANE_RIGHT) + { + if(t_bVertical) + { + lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; + lpRect->top = m_rcSplitter.top; + lpRect->right = m_rcSplitter.right; + lpRect->bottom = m_rcSplitter.bottom; + } + else + { + lpRect->left = m_rcSplitter.left; + lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; + lpRect->right = m_rcSplitter.right; + lpRect->bottom = m_rcSplitter.bottom; + } + } + else + { + bRet = false; + } + return bRet; + } + + bool IsOverSplitterRect(int x, int y) const + { + // -1 == don't check + return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) && + (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom))); + } + + bool IsOverSplitterBar(int x, int y) const + { + if(m_nSinglePane != SPLIT_PANE_NONE) + return false; + if(m_xySplitterPos == -1 || !IsOverSplitterRect(x, y)) + return false; + int xy = t_bVertical ? x : y; + int xyOff = t_bVertical ? m_rcSplitter.left : m_rcSplitter.top; + return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge)); + } + + void DrawGhostBar() + { + RECT rect = { 0, 0, 0, 0 }; + if(GetSplitterBarRect(&rect)) + { + // invert the brush pattern (looks just like frame window sizing) + T* pT = static_cast(this); + CWindowDC dc(pT->m_hWnd); + CBrush brush = CDCHandle::GetHalftoneBrush(); + if(brush.m_hBrush != NULL) + { + CBrushHandle brushOld = dc.SelectBrush(brush); + dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); + dc.SelectBrush(brushOld); + } + } + } + + void GetSystemSettings(bool bUpdate) + { +#ifndef _WIN32_WCE + m_cxySplitBar = ::GetSystemMetrics(t_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME); +#else // CE specific + m_cxySplitBar = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE); +#endif // _WIN32_WCE + + T* pT = static_cast(this); + if((pT->GetExStyle() & WS_EX_CLIENTEDGE)) + { + m_cxyBarEdge = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE); + m_cxyMin = 0; + } + else + { + m_cxyBarEdge = 0; + m_cxyMin = 2 * ::GetSystemMetrics(t_bVertical ? SM_CXEDGE : SM_CYEDGE); + } + +#ifndef _WIN32_WCE + ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0); +#endif // !_WIN32_WCE + + if(bUpdate) + UpdateSplitterLayout(); + } + + bool IsProportional() const + { + return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0); + } + + void StoreProportionalPos() + { + int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); + if(cxyTotal > 0) + m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal); + else + m_nProportionalPos = 0; + ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos - %i\n"), m_nProportionalPos); + } + + void UpdateProportionalPos() + { + int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); + if(cxyTotal > 0) + { + int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax); + m_bUpdateProportionalPos = false; + T* pT = static_cast(this); + pT->SetSplitterPos(xyNewPos, false); + } + } + + bool IsRightAligned() const + { + return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0); + } + + void StoreRightAlignPos() + { + int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); + if(cxyTotal > 0) + m_nProportionalPos = cxyTotal - m_xySplitterPos; + else + m_nProportionalPos = 0; + ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos - %i\n"), m_nProportionalPos); + } + + void UpdateRightAlignPos() + { + int cxyTotal = t_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); + if(cxyTotal > 0) + { + m_bUpdateProportionalPos = false; + T* pT = static_cast(this); + pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false); + } + } + + bool IsInteractive() const + { + return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0); + } +}; + +template HCURSOR CSplitterImpl< T, t_bVertical>::m_hCursor = NULL; + + +/////////////////////////////////////////////////////////////////////////////// +// CSplitterWindowImpl - Implements a splitter window + +template +class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T , t_bVertical > +{ +public: + DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW) + + typedef CSplitterImpl< T , t_bVertical > _baseClass; + + BEGIN_MSG_MAP(CSplitterWindowImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_SIZE, OnSize) + CHAIN_MSG_MAP(_baseClass) + FORWARD_NOTIFICATIONS() + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + // handled, no background painting needed + return 1; + } + + LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if(wParam != SIZE_MINIMIZED) + SetSplitterRect(); + + bHandled = FALSE; + return 1; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CSplitterWindow - Implements a splitter window to be used as is + +template +class CSplitterWindowT : public CSplitterWindowImpl, t_bVertical> +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW) +}; + +typedef CSplitterWindowT CSplitterWindow; +typedef CSplitterWindowT CHorSplitterWindow; + +}; // namespace WTL + +#endif // __ATLSPLIT_H__ diff --git a/wtl/wtl/include/atltheme.h b/wtl/wtl/include/atltheme.h new file mode 100644 index 00000000..4c0725f4 --- /dev/null +++ b/wtl/wtl/include/atltheme.h @@ -0,0 +1,1218 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLTHEME_H__ +#define __ATLTHEME_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifdef _WIN32_WCE + #error atltheme.h is not supported on Windows CE +#endif + +#ifndef __ATLAPP_H__ + #error atltheme.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atltheme.h requires atlwin.h to be included first +#endif + +#if (_WIN32_WINNT < 0x0501) + #error atltheme.h requires _WIN32_WINNT >= 0x0501 +#endif // (_WIN32_WINNT < 0x0501) + +#if defined(_WTL_USE_VSSYM32) || (defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)) + #include +#else + #include +#endif + +#include +#pragma comment(lib, "uxtheme.lib") + +// Note: To create an application that also runs on older versions of Windows, +// use delay load of uxtheme.dll and ensure that no calls to the Theme API are +// made if theming is not supported. It is enough to check if m_hTheme is NULL. +// Example: +// if(m_hTheme != NULL) +// { +// DrawThemeBackground(dc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL); +// DrawThemeText(dc, BP_PUSHBUTTON, PBS_NORMAL, L"Button", -1, DT_SINGLELINE | DT_CENTER | DT_VCENTER, 0, &rect); +// } +// else +// { +// dc.DrawFrameControl(&rect, DFC_BUTTON, DFCS_BUTTONPUSH); +// dc.DrawText(_T("Button"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); +// } +// +// Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, +// and add uxtheme.dll in the Linker.Input.Delay Loaded DLLs section of the +// project properties. +#if (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) + #pragma comment(lib, "delayimp.lib") + #pragma comment(linker, "/delayload:uxtheme.dll") +#endif // (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) + +// Hack: Signatures in uxtheme.h changed - the only way to check which variant of uxtheme.h +// is included is to check for presence of new defines MAX_THEMECOLOR and MAX_THEMESIZE +#ifndef _WTL_NEW_UXTHEME + #if defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) + #define _WTL_NEW_UXTHEME + #endif // defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) +#endif // _WTL_NEW_UXTHEME + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CTheme +// CThemeImpl +// +// CBufferedPaint +// CBufferedPaintImpl +// CBufferedPaintWindowImpl +// CBufferedAnimation +// CBufferedAnimationImpl +// CBufferedAnimationWindowImpl +// +// Global functions: +// AtlDrawThemeClientEdge() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// CTheme - wrapper for theme handle + +class CTheme +{ +public: +// Data members + HTHEME m_hTheme; + static int m_nIsThemingSupported; + +// Constructor + CTheme(HTHEME hTheme = NULL) : m_hTheme(hTheme) + { + IsThemingSupported(); + } + +// Operators and helpers + bool IsThemeNull() const + { + return (m_hTheme == NULL); + } + + CTheme& operator =(HTHEME hTheme) + { + m_hTheme = hTheme; + return *this; + } + + operator HTHEME() const + { + return m_hTheme; + } + + void Attach(HTHEME hTheme) + { + m_hTheme = hTheme; + } + + HTHEME Detach() + { + HTHEME hTheme = m_hTheme; + m_hTheme = NULL; + return hTheme; + } + +// Theme support helper + static bool IsThemingSupported() + { + if(m_nIsThemingSupported == -1) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CTheme::IsThemingSupported.\n")); + ATLASSERT(FALSE); + return false; + } + + if(m_nIsThemingSupported == -1) + { + HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); + m_nIsThemingSupported = (hThemeDLL != NULL) ? 1 : 0; + if(hThemeDLL != NULL) + ::FreeLibrary(hThemeDLL); + } + + lock.Unlock(); + } + + ATLASSERT(m_nIsThemingSupported != -1); + return (m_nIsThemingSupported == 1); + } + +// Operations and theme properties + HTHEME OpenThemeData(HWND hWnd, LPCWSTR pszClassList) + { + if(!IsThemingSupported()) + return NULL; + + ATLASSERT(m_hTheme == NULL); + m_hTheme = ::OpenThemeData(hWnd, pszClassList); + return m_hTheme; + } + + HRESULT CloseThemeData() + { + HRESULT hRet = S_FALSE; + if(m_hTheme != NULL) + { + hRet = ::CloseThemeData(m_hTheme); + if(SUCCEEDED(hRet)) + m_hTheme = NULL; + } + return hRet; + } + + HRESULT DrawThemeBackground(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = NULL) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeBackground(m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect); + } + + HRESULT DrawThemeBackgroundEx(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS* pOptions = NULL) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeBackgroundEx(m_hTheme, hDC, nPartID, nStateID, pRect, pOptions); + } + + HRESULT DrawThemeText(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeText(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect); + } + + HRESULT GetThemeBackgroundContentRect(HDC hDC, int nPartID, int nStateID, LPCRECT pBoundingRect, LPRECT pContentRect) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBackgroundContentRect(m_hTheme, hDC, nPartID, nStateID, pBoundingRect, pContentRect); + } + + HRESULT GetThemeBackgroundExtent(HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBackgroundExtent(m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect); + } + + HRESULT GetThemePartSize(HDC hDC, int nPartID, int nStateID, LPRECT pRect, enum THEMESIZE eSize, LPSIZE pSize) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize); + } + + HRESULT GetThemeTextExtent(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT pBoundingRect, LPRECT pExtentRect) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeTextExtent(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect); + } + + HRESULT GetThemeTextMetrics(HDC hDC, int nPartID, int nStateID, PTEXTMETRICW pTextMetric) const + { + ATLASSERT(m_hTheme != NULL); +#ifdef _WTL_NEW_UXTHEME + return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, pTextMetric); +#else // !_WTL_NEW_UXTHEME + // Note: The cast to PTEXTMETRIC is because uxtheme.h incorrectly uses it instead of PTEXTMETRICW + return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, (PTEXTMETRIC)pTextMetric); +#endif // !_WTL_NEW_UXTHEME + } + + HRESULT GetThemeBackgroundRegion(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN* pRegion) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBackgroundRegion(m_hTheme, hDC, nPartID, nStateID, pRect, pRegion); + } + + HRESULT HitTestThemeBackground(HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD* pwHitTestCode) const + { + ATLASSERT(m_hTheme != NULL); + return ::HitTestThemeBackground(m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode); + } + + HRESULT DrawThemeEdge(HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = NULL) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeEdge(m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect); + } + + HRESULT DrawThemeIcon(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeIcon(m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex); + } + + BOOL IsThemePartDefined(int nPartID, int nStateID) const + { + ATLASSERT(m_hTheme != NULL); + return ::IsThemePartDefined(m_hTheme, nPartID, nStateID); + } + + BOOL IsThemeBackgroundPartiallyTransparent(int nPartID, int nStateID) const + { + ATLASSERT(m_hTheme != NULL); + return ::IsThemeBackgroundPartiallyTransparent(m_hTheme, nPartID, nStateID); + } + + HRESULT GetThemeColor(int nPartID, int nStateID, int nPropID, COLORREF* pColor) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeColor(m_hTheme, nPartID, nStateID, nPropID, pColor); + } + + HRESULT GetThemeMetric(HDC hDC, int nPartID, int nStateID, int nPropID, int* pnVal) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeMetric(m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal); + } + + HRESULT GetThemeString(int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeString(m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars); + } + + HRESULT GetThemeBool(int nPartID, int nStateID, int nPropID, BOOL* pfVal) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBool(m_hTheme, nPartID, nStateID, nPropID, pfVal); + } + + HRESULT GetThemeInt(int nPartID, int nStateID, int nPropID, int* pnVal) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeInt(m_hTheme, nPartID, nStateID, nPropID, pnVal); + } + + HRESULT GetThemeEnumValue(int nPartID, int nStateID, int nPropID, int* pnVal) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeEnumValue(m_hTheme, nPartID, nStateID, nPropID, pnVal); + } + + HRESULT GetThemePosition(int nPartID, int nStateID, int nPropID, LPPOINT pPoint) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemePosition(m_hTheme, nPartID, nStateID, nPropID, pPoint); + } + + // deprecated + HRESULT GetThemeFont(int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONTW* pFont) const + { + ATLASSERT(m_hTheme != NULL); +#ifdef _WTL_NEW_UXTHEME + return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); +#else // !_WTL_NEW_UXTHEME + // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* + return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); +#endif // !_WTL_NEW_UXTHEME + } + + HRESULT GetThemeFont(HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONTW* pFont) const + { + ATLASSERT(m_hTheme != NULL); +#ifdef _WTL_NEW_UXTHEME + return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); +#else // !_WTL_NEW_UXTHEME + // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* + return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); +#endif // !_WTL_NEW_UXTHEME + } + + HRESULT GetThemeRect(int nPartID, int nStateID, int nPropID, LPRECT pRect) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeRect(m_hTheme, nPartID, nStateID, nPropID, pRect); + } + + HRESULT GetThemeMargins(HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeMargins(m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins); + } + + HRESULT GetThemeIntList(int nPartID, int nStateID, int nPropID, INTLIST* pIntList) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeIntList(m_hTheme, nPartID, nStateID, nPropID, pIntList); + } + + HRESULT GetThemePropertyOrigin(int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN* pOrigin) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemePropertyOrigin(m_hTheme, nPartID, nStateID, nPropID, pOrigin); + } + + HRESULT GetThemeFilename(int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeFilename(m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars); + } + + COLORREF GetThemeSysColor(int nColorID) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysColor(m_hTheme, nColorID); + } + + HBRUSH GetThemeSysColorBrush(int nColorID) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysColorBrush(m_hTheme, nColorID); + } + + int GetThemeSysSize(int nSizeID) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysSize(m_hTheme, nSizeID); + } + + BOOL GetThemeSysBool(int nBoolID) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysBool(m_hTheme, nBoolID); + } + + HRESULT GetThemeSysFont(int nFontID, LOGFONTW* plf) const + { + ATLASSERT(m_hTheme != NULL); +#ifdef _WTL_NEW_UXTHEME + return ::GetThemeSysFont(m_hTheme, nFontID, plf); +#else // !_WTL_NEW_UXTHEME + // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* + return ::GetThemeSysFont(m_hTheme, nFontID, (LOGFONT*)plf); +#endif // !_WTL_NEW_UXTHEME + } + + HRESULT GetThemeSysString(int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysString(m_hTheme, nStringID, pszStringBuff, cchMaxStringChars); + } + + HRESULT GetThemeSysInt(int nIntID, int* pnValue) const + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeSysInt(m_hTheme, nIntID, pnValue); + } + +#ifdef _WTL_NEW_UXTHEME + HTHEME OpenThemeDataEx(HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags) + { + if(!IsThemingSupported()) + return NULL; + + ATLASSERT(m_hTheme == NULL); + m_hTheme = ::OpenThemeDataEx(hWnd, pszClassList, dwFlags); + return m_hTheme; + } + + HRESULT DrawThemeTextEx(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS* pOptions) + { + ATLASSERT(m_hTheme != NULL); + return ::DrawThemeTextEx(m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions); + } + + HRESULT GetThemeTransitionDuration(int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD& dwDuration) + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeTransitionDuration(m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration); + } +#endif // _WTL_NEW_UXTHEME + +#if (_WIN32_WINNT >= 0x0600) + HRESULT GetThemeBitmap(int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP& hBitmap) + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeBitmap(m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap); + } + + HRESULT GetThemeStream(int nPartID, int nStateID, int nPropID, VOID** ppvStream, DWORD* pcbStream, HINSTANCE hInstance) + { + ATLASSERT(m_hTheme != NULL); + return ::GetThemeStream(m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance); + } +#endif // (_WIN32_WINNT >= 0x0600) +}; + +__declspec(selectany) int CTheme::m_nIsThemingSupported = -1; + + +/////////////////////////////////////////////////////////////////////////////// +// CThemeImpl - theme support implementation + +// Derive from this class to implement window with theme support. +// Example: +// class CMyThemeWindow : public CWindowImpl, public CThemeImpl +// { +// ... +// BEGIN_MSG_MAP(CMyThemeWindow) +// CHAIN_MSG_MAP(CThemeImpl) +// ... +// END_MSG_MAP() +// ... +// }; +// +// If you set theme class list, the class will automaticaly open/close/reopen theme data. + + +// Helper for drawing theme client edge +inline bool AtlDrawThemeClientEdge(HTHEME hTheme, HWND hWnd, HRGN hRgnUpdate = NULL, HBRUSH hBrush = NULL, int nPartID = 0, int nStateID = 0) +{ + ATLASSERT(hTheme != NULL); + ATLASSERT(::IsWindow(hWnd)); + + CWindowDC dc(hWnd); + if(dc.IsNull()) + return false; + + // Get border size + int cxBorder = GetSystemMetrics(SM_CXBORDER); + int cyBorder = GetSystemMetrics(SM_CYBORDER); + if(SUCCEEDED(::GetThemeInt(hTheme, nPartID, nStateID, TMT_SIZINGBORDERWIDTH, &cxBorder))) + cyBorder = cxBorder; + + RECT rect; + ::GetWindowRect(hWnd, &rect); + + // Remove the client edge from the update region + int cxEdge = GetSystemMetrics(SM_CXEDGE); + int cyEdge = GetSystemMetrics(SM_CYEDGE); + ::InflateRect(&rect, -cxEdge, -cyEdge); + CRgn rgn; + rgn.CreateRectRgnIndirect(&rect); + if(rgn.IsNull()) + return false; + + if(hRgnUpdate != NULL) + rgn.CombineRgn(hRgnUpdate, rgn, RGN_AND); + + ::OffsetRect(&rect, -rect.left, -rect.top); + + ::OffsetRect(&rect, cxEdge, cyEdge); + dc.ExcludeClipRect(&rect); + ::InflateRect(&rect, cxEdge, cyEdge); + + ::DrawThemeBackground(hTheme, dc, nPartID, nStateID, &rect, NULL); + + // Use background brush too, since theme border might not cover everything + if(cxBorder < cxEdge && cyBorder < cyEdge) + { + if(hBrush == NULL) +// need conditional code because types don't match in winuser.h +#ifdef _WIN64 + hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND); +#else + hBrush = (HBRUSH)UlongToPtr(::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND)); +#endif + + ::InflateRect(&rect, cxBorder - cxEdge, cyBorder - cyEdge); + dc.FillRect(&rect, hBrush); + } + + ::DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0L); + + return true; +} + + +// Theme extended styles +#define THEME_EX_3DCLIENTEDGE 0x00000001 +#define THEME_EX_THEMECLIENTEDGE 0x00000002 + +template +class CThemeImpl : public TBase +{ +public: +// Data members + LPWSTR m_lpstrThemeClassList; + DWORD m_dwExtendedStyle; // theme specific extended styles + +// Constructor & destructor + CThemeImpl() : m_lpstrThemeClassList(NULL), m_dwExtendedStyle(0) + { } + + ~CThemeImpl() + { + delete [] m_lpstrThemeClassList; + } + +// Attributes + bool SetThemeClassList(LPCWSTR lpstrThemeClassList) + { + if(m_lpstrThemeClassList != NULL) + { + delete [] m_lpstrThemeClassList; + m_lpstrThemeClassList = NULL; + } + + if(lpstrThemeClassList == NULL) + return true; + + int cchLen = lstrlenW(lpstrThemeClassList) + 1; + ATLTRY(m_lpstrThemeClassList = new WCHAR[cchLen]); + if(m_lpstrThemeClassList == NULL) + return false; + + SecureHelper::strcpyW_x(m_lpstrThemeClassList, cchLen, lpstrThemeClassList); + + return true; + } + + bool GetThemeClassList(LPWSTR lpstrThemeClassList, int cchListBuffer) const + { + int cchLen = lstrlenW(m_lpstrThemeClassList) + 1; + if(cchListBuffer < cchLen) + return false; + + SecureHelper::strcpyW_x(lpstrThemeClassList, cchListBuffer, m_lpstrThemeClassList); + + return true; + } + + LPCWSTR GetThemeClassList() const + { + return m_lpstrThemeClassList; + } + + DWORD SetThemeExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) + { + DWORD dwPrevStyle = m_dwExtendedStyle; + if(dwMask == 0) + m_dwExtendedStyle = dwExtendedStyle; + else + m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); + return dwPrevStyle; + } + + DWORD GetThemeExtendedStyle() const + { + return m_dwExtendedStyle; + } + +// Operations + HTHEME OpenThemeData() + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + ATLASSERT(m_lpstrThemeClassList != NULL); + if(m_lpstrThemeClassList == NULL) + return NULL; + CloseThemeData(); + return TBase::OpenThemeData(pT->m_hWnd, m_lpstrThemeClassList); + } + + HTHEME OpenThemeData(LPCWSTR pszClassList) + { + if(!SetThemeClassList(pszClassList)) + return NULL; + return OpenThemeData(); + } + + HRESULT SetWindowTheme(LPCWSTR pszSubAppName, LPCWSTR pszSubIDList) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::SetWindowTheme(pT->m_hWnd, pszSubAppName, pszSubIDList); + } + + HTHEME GetWindowTheme() const + { + if(!IsThemingSupported()) + return NULL; + + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::GetWindowTheme(pT->m_hWnd); + } + + HRESULT EnableThemeDialogTexture(DWORD dwFlags) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::EnableThemeDialogTexture(pT->m_hWnd, dwFlags); + } + + BOOL IsThemeDialogTextureEnabled() const + { + if(!IsThemingSupported()) + return FALSE; + + const T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::IsThemeDialogTextureEnabled(pT->m_hWnd); + } + + HRESULT DrawThemeParentBackground(HDC hDC, const RECT* pRect = NULL) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); +#ifdef _WTL_NEW_UXTHEME + return ::DrawThemeParentBackground(pT->m_hWnd, hDC, pRect); +#else + return ::DrawThemeParentBackground(pT->m_hWnd, hDC, (RECT*)pRect); +#endif + } + +#ifdef _WTL_NEW_UXTHEME + HRESULT SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type, PVOID pvAttribute, DWORD cbAttribute) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::SetWindowThemeAttribute(pT->m_hWnd, type, pvAttribute, cbAttribute); + } + + HRESULT SetWindowThemeNonClientAttributes(DWORD dwAttributes, DWORD dwMask) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + WTA_OPTIONS opt = { dwAttributes, dwMask }; + return ::SetWindowThemeAttribute(pT->m_hWnd, WTA_NONCLIENT, (PVOID)&opt, sizeof(opt)); + } + + HRESULT DrawThemeParentBackgroundEx(HDC hDC, DWORD dwFlags, const RECT* lpRect = NULL) + { + if(!IsThemingSupported()) + return S_FALSE; + + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + return ::DrawThemeParentBackgroundEx(pT->m_hWnd, hDC, dwFlags, lpRect); + } +#endif // _WTL_NEW_UXTHEME + +// Message map and handlers + // Note: If you handle any of these messages in your derived class, + // it is better to put CHAIN_MSG_MAP at the start of your message map. + BEGIN_MSG_MAP(CThemeImpl) + MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_DESTROY, OnDestroy) + MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) + MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) + END_MSG_MAP() + + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if(m_lpstrThemeClassList != NULL) + OpenThemeData(); + bHandled = FALSE; + return 1; + } + + LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + CloseThemeData(); + bHandled = FALSE; + return 1; + } + + LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + CloseThemeData(); + if(m_lpstrThemeClassList != NULL) + OpenThemeData(); + bHandled = FALSE; + return 1; + } + + LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + LRESULT lRet = 0; + bHandled = FALSE; + if(IsThemingSupported() && ((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)) + { + if((m_dwExtendedStyle & THEME_EX_3DCLIENTEDGE) != 0) + { + lRet = ::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam); + bHandled = TRUE; + } + else if((m_hTheme != NULL) && ((m_dwExtendedStyle & THEME_EX_THEMECLIENTEDGE) != 0)) + { + HRGN hRgn = (wParam != 1) ? (HRGN)wParam : NULL; + if(pT->DrawThemeClientEdge(hRgn)) + bHandled = TRUE; + } + } + return lRet; + } + +// Drawing helper + bool DrawThemeClientEdge(HRGN hRgnUpdate) + { + T* pT = static_cast(this); + return AtlDrawThemeClientEdge(m_hTheme, pT->m_hWnd, hRgnUpdate, NULL, 0, 0); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Buffered Paint and Animation + +#ifdef _WTL_NEW_UXTHEME + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedPaintBase - Buffered Paint support for othe classes + +class CBufferedPaintBase +{ +public: + static int m_nIsBufferedPaintSupported; + + CBufferedPaintBase() + { + if(IsBufferedPaintSupported()) + ATLVERIFY(SUCCEEDED(::BufferedPaintInit())); + } + + ~CBufferedPaintBase() + { + if(IsBufferedPaintSupported()) + ATLVERIFY(SUCCEEDED(::BufferedPaintUnInit())); + } + + static bool IsBufferedPaintSupported() + { + if(m_nIsBufferedPaintSupported == -1) + { + CStaticDataInitCriticalSectionLock lock; + if(FAILED(lock.Lock())) + { + ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CBufferedPaintBase::IsBufferedPaintSupported.\n")); + ATLASSERT(FALSE); + return false; + } + + if(m_nIsBufferedPaintSupported == -1) + m_nIsBufferedPaintSupported = RunTimeHelper::IsVista() ? 1 : 0; + + lock.Unlock(); + } + + ATLASSERT(m_nIsBufferedPaintSupported != -1); + return (m_nIsBufferedPaintSupported == 1); + } +}; + +__declspec(selectany) int CBufferedPaintBase::m_nIsBufferedPaintSupported = -1; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedPaint - support for buffered paint functions + +class CBufferedPaint +{ +public: + HPAINTBUFFER m_hPaintBuffer; + + CBufferedPaint() : m_hPaintBuffer(NULL) + { } + + ~CBufferedPaint() + { + ATLVERIFY(SUCCEEDED(End())); + } + + bool IsNull() const + { + return (m_hPaintBuffer == NULL); + } + + HPAINTBUFFER Begin(HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, HDC* phdcPaint) + { + ATLASSERT(m_hPaintBuffer == NULL); + m_hPaintBuffer = ::BeginBufferedPaint(hdcTarget, prcTarget, dwFormat, pPaintParams, phdcPaint); + return m_hPaintBuffer; + } + + HRESULT End(BOOL bUpdate = TRUE) + { + HRESULT hRet = S_FALSE; + if(m_hPaintBuffer != NULL) + { + hRet = ::EndBufferedPaint(m_hPaintBuffer, bUpdate); + m_hPaintBuffer = NULL; + } + return hRet; + } + + HRESULT GetTargetRect(LPRECT pRect) const + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::GetBufferedPaintTargetRect(m_hPaintBuffer, pRect); + } + + HDC GetTargetDC() const + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::GetBufferedPaintTargetDC(m_hPaintBuffer); + } + + HDC GetPaintDC() const + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::GetBufferedPaintDC(m_hPaintBuffer); + } + + HRESULT GetBits(RGBQUAD** ppbBuffer, int* pcxRow) const + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::GetBufferedPaintBits(m_hPaintBuffer, ppbBuffer, pcxRow); + } + + HRESULT Clear(const RECT* pRect = NULL) + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::BufferedPaintClear(m_hPaintBuffer, pRect); + } + + HRESULT SetAlpha(BYTE alpha, const RECT* pRect = NULL) + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, alpha); + } + + HRESULT MakeOpaque(const RECT* pRect = NULL) + { + ATLASSERT(m_hPaintBuffer != NULL); + return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, 255); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedPaintImpl - provides buffered paint for any window + +template +class ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase +{ +public: + CBufferedPaint m_BufferedPaint; + BP_BUFFERFORMAT m_dwFormat; + BP_PAINTPARAMS m_PaintParams; + + CBufferedPaintImpl() : m_dwFormat(BPBF_TOPDOWNDIB) + { + memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); + m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); + } + +// Message map and handlers + BEGIN_MSG_MAP(CBufferedPaintImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + if(wParam != NULL) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + pT->DoPaint((HDC)wParam, rect); + } + else + { + CPaintDC dc(pT->m_hWnd); + pT->DoBufferedPaint(dc.m_hDC, dc.m_ps.rcPaint); + } + + return 0; + } + +// Overrideables + void DoBufferedPaint(CDCHandle dc, RECT& rect) + { + HDC hDCPaint = NULL; + if(IsBufferedPaintSupported()) + m_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint); + + T* pT = static_cast(this); + if(hDCPaint != NULL) + pT->DoPaint(hDCPaint, rect); + else + pT->DoPaint(dc.m_hDC, rect); + + if(IsBufferedPaintSupported()) + m_BufferedPaint.End(); + } + + void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/) + { + // must be implemented in a derived class + ATLASSERT(FALSE); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedPaintWindowImpl - implements a window that uses buffered paint + +template +class ATL_NO_VTABLE CBufferedPaintWindowImpl : + public ATL::CWindowImpl, + public CBufferedPaintImpl< T > +{ +public: + BEGIN_MSG_MAP(CBufferedPaintWindowImpl) + CHAIN_MSG_MAP(CBufferedPaintImpl< T >) + END_MSG_MAP() +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedAnimation - support for buffered animation + +class CBufferedAnimation +{ +public: + HANIMATIONBUFFER m_hAnimationBuffer; + + CBufferedAnimation() : m_hAnimationBuffer(NULL) + { } + + ~CBufferedAnimation() + { + ATLVERIFY(SUCCEEDED(End())); + } + + bool IsNull() const + { + return (m_hAnimationBuffer == NULL); + } + + HANIMATIONBUFFER Begin(HWND hWnd, HDC hDCTarget, const RECT* pRectTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, BP_ANIMATIONPARAMS* pAnimationParams, HDC* phdcFrom, HDC* phdcTo) + { + ATLASSERT(m_hAnimationBuffer == NULL); + m_hAnimationBuffer = ::BeginBufferedAnimation(hWnd, hDCTarget, pRectTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo); + return m_hAnimationBuffer; + } + + HRESULT End(BOOL bUpdate = TRUE) + { + HRESULT hRet = S_FALSE; + if(m_hAnimationBuffer != NULL) + { + hRet = ::EndBufferedAnimation(m_hAnimationBuffer, bUpdate); + m_hAnimationBuffer = NULL; + } + return hRet; + } + + static bool IsRendering(HWND hWnd, HDC hDC) + { + return (::BufferedPaintRenderAnimation(hWnd, hDC) != FALSE); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedAnimationImpl - provides buffered animation support for any window + +// Note: You can either use m_State and m_NewState to store the state information +// for the animation change, or map your state to those data members. DoPaint() +// should only rely on the state information that is passed to it. + +template +class ATL_NO_VTABLE CBufferedAnimationImpl : public CBufferedPaintBase +{ +public: + BP_BUFFERFORMAT m_dwFormat; + BP_PAINTPARAMS m_PaintParams; + BP_ANIMATIONPARAMS m_AnimationParams; + + TState m_State; + TState m_NewState; + + CBufferedAnimationImpl(TState InitialState) : m_dwFormat(BPBF_TOPDOWNDIB) + { + memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); + m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); + + memset(&m_AnimationParams, 0, sizeof(BP_ANIMATIONPARAMS)); + m_AnimationParams.cbSize = sizeof(BP_ANIMATIONPARAMS); + m_AnimationParams.style = BPAS_LINEAR; + m_AnimationParams.dwDuration = 500; + + T* pT = static_cast(this); + pT->SetState(InitialState); + pT->SetNewState(InitialState); + } + + DWORD GetDuration() const + { + return m_AnimationParams.dwDuration; + } + + void SetDuration(DWORD dwDuration) + { + m_AnimationParams.dwDuration = dwDuration; + } + + void DoAnimation(TState NewState, const RECT* pRect = NULL) + { + T* pT = static_cast(this); + pT->SetNewState(NewState); + + pT->InvalidateRect(pRect, FALSE); + pT->UpdateWindow(); + + pT->SetState(NewState); + } + +// Message map and handlers + BEGIN_MSG_MAP(CBufferedAnimationImpl) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER(WM_PAINT, OnPaint) + MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) + END_MSG_MAP() + + LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + return 1; // no background needed + } + + LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + if(wParam != NULL) + { + RECT rect = { 0 }; + pT->GetClientRect(&rect); + pT->DoPaint((HDC)wParam, rect, m_NewState); + } + else + { + CPaintDC dc(pT->m_hWnd); + pT->DoAnimationPaint(dc.m_hDC, dc.m_ps.rcPaint); + } + + return 0; + } + +// Overrideables + void SetState(TState State) + { + m_State = State; + } + + void SetNewState(TState State) + { + m_NewState = State; + } + + bool AreStatesEqual() const + { + return (m_State == m_NewState); + } + + void DoAnimationPaint(CDCHandle dc, RECT& rect) + { + T* pT = static_cast(this); + if(IsBufferedPaintSupported() && CBufferedAnimation::IsRendering(pT->m_hWnd, dc)) + return; + + DWORD dwDurationSave = m_AnimationParams.dwDuration; + if(pT->AreStatesEqual()) + m_AnimationParams.dwDuration = 0; + + HDC hdcFrom = NULL, hdcTo = NULL; + CBufferedAnimation ba; + if(IsBufferedPaintSupported()) + ba.Begin(pT->m_hWnd, dc, &rect, m_dwFormat, &m_PaintParams, &m_AnimationParams, &hdcFrom, &hdcTo); + + if(!ba.IsNull()) + { + if(hdcFrom != NULL) + pT->DoPaint(hdcFrom, rect, m_State); + + if (hdcTo != NULL) + pT->DoPaint(hdcTo, rect, m_NewState); + } + else + { + pT->DoPaint(dc.m_hDC, rect, m_NewState); + } + + m_AnimationParams.dwDuration = dwDurationSave; + } + + void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/, TState /*State*/) + { + // must be implemented in a derived class + ATLASSERT(FALSE); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CBufferedAnimationWindowImpl - implements a window that uses buffered animation + +template +class ATL_NO_VTABLE CBufferedAnimationWindowImpl : + public ATL::CWindowImpl, + public CBufferedAnimationImpl< T, TState > +{ +public: + CBufferedAnimationWindowImpl(TState InitialState) : CBufferedAnimationImpl< T, TState >(InitialState) + { } + + typedef CBufferedAnimationImpl< T, TState > _baseBufferedAnimation; + BEGIN_MSG_MAP(CBufferedAnimationWindowImpl) + CHAIN_MSG_MAP(_baseBufferedAnimation) + END_MSG_MAP() +}; + +#endif // _WTL_NEW_UXTHEME + +}; // namespace WTL + +#endif // __ATLTHEME_H__ diff --git a/wtl/wtl/include/atluser.h b/wtl/wtl/include/atluser.h new file mode 100644 index 00000000..6570b8bb --- /dev/null +++ b/wtl/wtl/include/atluser.h @@ -0,0 +1,1162 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLUSER_H__ +#define __ATLUSER_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atluser.h requires atlapp.h to be included first +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CMenuItemInfo +// CMenuT +// CAcceleratorT +// CIconT +// CCursorT +// CResource +// +// Global functions: +// AtlMessageBox() + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// AtlMessageBox - accepts both memory and resource based strings + +inline int AtlMessageBox(HWND hWndOwner, ATL::_U_STRINGorID message, ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uType = MB_OK | MB_ICONINFORMATION) +{ + ATLASSERT(hWndOwner == NULL || ::IsWindow(hWndOwner)); + + LPTSTR lpstrMessage = NULL; + if(IS_INTRESOURCE(message.m_lpstr)) + { + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrMessage = new TCHAR[nLen]); + if(lpstrMessage == NULL) + { + ATLASSERT(FALSE); + return 0; + } + int nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(message.m_lpstr), lpstrMessage, nLen); + if(nRes < nLen - 1) + break; + delete [] lpstrMessage; + lpstrMessage = NULL; + } + + message.m_lpstr = lpstrMessage; + } + + LPTSTR lpstrTitle = NULL; + if(IS_INTRESOURCE(title.m_lpstr) && LOWORD(title.m_lpstr) != 0) + { + for(int nLen = 256; ; nLen *= 2) + { + ATLTRY(lpstrTitle = new TCHAR[nLen]); + if(lpstrTitle == NULL) + { + ATLASSERT(FALSE); + return 0; + } + int nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(title.m_lpstr), lpstrTitle, nLen); + if(nRes < nLen - 1) + break; + delete [] lpstrTitle; + lpstrTitle = NULL; + } + + title.m_lpstr = lpstrTitle; + } + + int nRet = ::MessageBox(hWndOwner, message.m_lpstr, title.m_lpstr, uType); + + delete [] lpstrMessage; + delete [] lpstrTitle; + + return nRet; +} + + +/////////////////////////////////////////////////////////////////////////////// +// CMenu + +#if (WINVER >= 0x0500) + #ifndef MII_SIZEOF_STRUCT + #define MII_SIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) + #endif + #define MENUITEMINFO_SIZE_VERSION_400A MII_SIZEOF_STRUCT(MENUITEMINFOA, cch) + #define MENUITEMINFO_SIZE_VERSION_400W MII_SIZEOF_STRUCT(MENUITEMINFOW, cch) + #ifdef UNICODE + #define MENUITEMINFO_SIZE_VERSION_400 MENUITEMINFO_SIZE_VERSION_400W + #else + #define MENUITEMINFO_SIZE_VERSION_400 MENUITEMINFO_SIZE_VERSION_400A + #endif // !UNICODE +#endif // (WINVER >= 0x0500) + +class CMenuItemInfo : public MENUITEMINFO +{ +public: + CMenuItemInfo() + { + memset(this, 0, sizeof(MENUITEMINFO)); + cbSize = sizeof(MENUITEMINFO); +#if (WINVER >= 0x0500) + // adjust struct size if running on older version of Windows + if(AtlIsOldWindows()) + { + ATLASSERT(cbSize > MENUITEMINFO_SIZE_VERSION_400); // must be + cbSize = MENUITEMINFO_SIZE_VERSION_400; + } +#endif // (WINVER >= 0x0500) + } +}; + + +// forward declarations +template class CMenuT; +typedef CMenuT CMenuHandle; +typedef CMenuT CMenu; + + +template +class CMenuT +{ +public: +// Data members + HMENU m_hMenu; + +// Constructor/destructor/operators + CMenuT(HMENU hMenu = NULL) : m_hMenu(hMenu) + { } + + ~CMenuT() + { + if(t_bManaged && m_hMenu != NULL) + DestroyMenu(); + } + + CMenuT& operator =(HMENU hMenu) + { + Attach(hMenu); + return *this; + } + + void Attach(HMENU hMenuNew) + { + ATLASSERT(::IsMenu(hMenuNew)); + if(t_bManaged && m_hMenu != NULL && m_hMenu != hMenuNew) + ::DestroyMenu(m_hMenu); + m_hMenu = hMenuNew; + } + + HMENU Detach() + { + HMENU hMenu = m_hMenu; + m_hMenu = NULL; + return hMenu; + } + + operator HMENU() const { return m_hMenu; } + + bool IsNull() const { return (m_hMenu == NULL); } + + BOOL IsMenu() const + { + return ::IsMenu(m_hMenu); + } + +// Create/destroy methods + BOOL CreateMenu() + { + ATLASSERT(m_hMenu == NULL); + m_hMenu = ::CreateMenu(); + return (m_hMenu != NULL) ? TRUE : FALSE; + } + + BOOL CreatePopupMenu() + { + ATLASSERT(m_hMenu == NULL); + m_hMenu = ::CreatePopupMenu(); + return (m_hMenu != NULL) ? TRUE : FALSE; + } + + BOOL LoadMenu(ATL::_U_STRINGorID menu) + { + ATLASSERT(m_hMenu == NULL); + m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr); + return (m_hMenu != NULL) ? TRUE : FALSE; + } + +#ifndef _WIN32_WCE + BOOL LoadMenuIndirect(const void* lpMenuTemplate) + { + ATLASSERT(m_hMenu == NULL); + m_hMenu = ::LoadMenuIndirect(lpMenuTemplate); + return (m_hMenu != NULL) ? TRUE : FALSE; + } +#endif // !_WIN32_WCE + + BOOL DestroyMenu() + { + if (m_hMenu == NULL) + return FALSE; + BOOL bRet = ::DestroyMenu(m_hMenu); + if(bRet) + m_hMenu = NULL; + return bRet; + } + +// Menu Operations + BOOL DeleteMenu(UINT nPosition, UINT nFlags) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::DeleteMenu(m_hMenu, nPosition, nFlags); + } + + BOOL TrackPopupMenu(UINT nFlags, int x, int y, HWND hWnd, LPCRECT lpRect = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); +#ifndef _WIN32_WCE +#if (WINVER >= 0x0500) + x = _FixTrackMenuPopupX(x, y); +#endif // !(WINVER >= 0x0500) + return ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0, hWnd, lpRect); +#else // CE specific + lpRect; + return ::TrackPopupMenuEx(m_hMenu, nFlags, x, y, hWnd, NULL); +#endif // _WIN32_WCE + } + + BOOL TrackPopupMenuEx(UINT uFlags, int x, int y, HWND hWnd, LPTPMPARAMS lptpm = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + x = _FixTrackMenuPopupX(x, y); +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + return ::TrackPopupMenuEx(m_hMenu, uFlags, x, y, hWnd, lptpm); + } + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + // helper that fixes popup menu X position when it's off-screen + static int _FixTrackMenuPopupX(int x, int y) + { + POINT pt = { x, y }; + HMONITOR hMonitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONULL); + if(hMonitor == NULL) + { + HMONITOR hMonitorNear = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); + if(hMonitorNear != NULL) + { + MONITORINFO mi = { 0 }; + mi.cbSize = sizeof(MONITORINFO); + if(::GetMonitorInfo(hMonitorNear, &mi) != FALSE) + { + if(x < mi.rcWork.left) + x = mi.rcWork.left; + else if(x > mi.rcWork.right) + x = mi.rcWork.right; + } + } + } + + return x; + } + + BOOL GetMenuInfo(LPMENUINFO lpMenuInfo) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuInfo(m_hMenu, lpMenuInfo); + } + + BOOL SetMenuInfo(LPCMENUINFO lpMenuInfo) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::SetMenuInfo(m_hMenu, lpMenuInfo); + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) + +// Menu Item Operations + BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::AppendMenu(m_hMenu, nFlags, nIDNewItem, lpszNewItem); + } + + BOOL AppendMenu(UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::AppendMenu(m_hMenu, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem); + } + +#ifndef _WIN32_WCE + BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::AppendMenu(m_hMenu, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp); + } + + BOOL AppendMenu(UINT nFlags, HMENU hSubMenu, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::AppendMenu(m_hMenu, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp); + } +#endif // !_WIN32_WCE + + UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck) + { + ATLASSERT(::IsMenu(m_hMenu)); + return (UINT)::CheckMenuItem(m_hMenu, nIDCheckItem, nCheck); + } + + UINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::EnableMenuItem(m_hMenu, nIDEnableItem, nEnable); + } + +#ifndef _WIN32_WCE + BOOL HiliteMenuItem(HWND hWnd, UINT uIDHiliteItem, UINT uHilite) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::HiliteMenuItem(hWnd, m_hMenu, uIDHiliteItem, uHilite); + } + + int GetMenuItemCount() const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuItemCount(m_hMenu); + } + + UINT GetMenuItemID(int nPos) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuItemID(m_hMenu, nPos); + } + + UINT GetMenuState(UINT nID, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuState(m_hMenu, nID, nFlags); + } + + int GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags); + } + + int GetMenuStringLen(UINT nIDItem, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags); + } + +#ifndef _ATL_NO_COM + BOOL GetMenuString(UINT nIDItem, BSTR& bstrText, UINT nFlags) const + { + USES_CONVERSION; + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(bstrText == NULL); + + int nLen = GetMenuStringLen(nIDItem, nFlags); + if(nLen == 0) + { + bstrText = ::SysAllocString(OLESTR("")); + return (bstrText != NULL) ? TRUE : FALSE; + } + + nLen++; // increment to include terminating NULL char + CTempBuffer buff; + LPTSTR lpszText = buff.Allocate(nLen); + if(lpszText == NULL) + return FALSE; + + if(!GetMenuString(nIDItem, lpszText, nLen, nFlags)) + return FALSE; + + bstrText = ::SysAllocString(T2OLE(lpszText)); + return (bstrText != NULL) ? TRUE : FALSE; + } +#endif // !_ATL_NO_COM +#endif // !_WIN32_WCE + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + int GetMenuString(UINT nIDItem, _CSTRING_NS::CString& strText, UINT nFlags) const + { + ATLASSERT(::IsMenu(m_hMenu)); + + int nLen = GetMenuStringLen(nIDItem, nFlags); + if(nLen == 0) + return 0; + + nLen++; // increment to include terminating NULL char + LPTSTR lpstr = strText.GetBufferSetLength(nLen); + if(lpstr == NULL) + return 0; + int nRet = GetMenuString(nIDItem, lpstr, nLen, nFlags); + strText.ReleaseBuffer(); + return nRet; + } +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + + CMenuHandle GetSubMenu(int nPos) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return CMenuHandle(::GetSubMenu(m_hMenu, nPos)); + } + + BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::InsertMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem); + } + + BOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::InsertMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem); + } + +#ifndef _WIN32_WCE + BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::InsertMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp); + } + + BOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::InsertMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp); + } + + BOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::ModifyMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem); + } + + BOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem); + } + + BOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp); + } + + BOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp) + { + ATLASSERT(::IsMenu(m_hMenu)); + ATLASSERT(::IsMenu(hSubMenu)); + return ::ModifyMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp); + } +#endif // !_WIN32_WCE + + BOOL RemoveMenu(UINT nPosition, UINT nFlags) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::RemoveMenu(m_hMenu, nPosition, nFlags); + } + +#ifndef _WIN32_WCE + BOOL SetMenuItemBitmaps(UINT nPosition, UINT nFlags, HBITMAP hBmpUnchecked, HBITMAP hBmpChecked) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::SetMenuItemBitmaps(m_hMenu, nPosition, nFlags, hBmpUnchecked, hBmpChecked); + } +#endif // !_WIN32_WCE + + BOOL CheckMenuRadioItem(UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::CheckMenuRadioItem(m_hMenu, nIDFirst, nIDLast, nIDItem, nFlags); + } + + BOOL GetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return (BOOL)::GetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii); + } + + BOOL SetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) + { + ATLASSERT(::IsMenu(m_hMenu)); + return (BOOL)::SetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii); + } + +#ifndef _WIN32_WCE + BOOL InsertMenuItem(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) + { + ATLASSERT(::IsMenu(m_hMenu)); + return (BOOL)::InsertMenuItem(m_hMenu, uItem, bByPosition, lpmii); + } + + UINT GetMenuDefaultItem(BOOL bByPosition = FALSE, UINT uFlags = 0U) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuDefaultItem(m_hMenu, (UINT)bByPosition, uFlags); + } + + BOOL SetMenuDefaultItem(UINT uItem = (UINT)-1, BOOL bByPosition = FALSE) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::SetMenuDefaultItem(m_hMenu, uItem, (UINT)bByPosition); + } + + BOOL GetMenuItemRect(HWND hWnd, UINT uItem, LPRECT lprcItem) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuItemRect(hWnd, m_hMenu, uItem, lprcItem); + } + + int MenuItemFromPoint(HWND hWnd, POINT point) const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::MenuItemFromPoint(hWnd, m_hMenu, point); + } + +// Context Help Functions + BOOL SetMenuContextHelpId(DWORD dwContextHelpId) + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::SetMenuContextHelpId(m_hMenu, dwContextHelpId); + } + + DWORD GetMenuContextHelpId() const + { + ATLASSERT(::IsMenu(m_hMenu)); + return ::GetMenuContextHelpId(m_hMenu); + } +#endif // !_WIN32_WCE +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAccelerator + +template +class CAcceleratorT +{ +public: + HACCEL m_hAccel; + +// Constructor/destructor/operators + CAcceleratorT(HACCEL hAccel = NULL) : m_hAccel(hAccel) + { } + + ~CAcceleratorT() + { + if(t_bManaged && m_hAccel != NULL) + ::DestroyAcceleratorTable(m_hAccel); + } + + CAcceleratorT& operator =(HACCEL hAccel) + { + Attach(hAccel); + return *this; + } + + void Attach(HACCEL hAccel) + { + if(t_bManaged && m_hAccel != NULL) + ::DestroyAcceleratorTable(m_hAccel); + m_hAccel = hAccel; + } + + HACCEL Detach() + { + HACCEL hAccel = m_hAccel; + m_hAccel = NULL; + return hAccel; + } + + operator HACCEL() const { return m_hAccel; } + + bool IsNull() const { return m_hAccel == NULL; } + +// Create/destroy methods + HACCEL LoadAccelerators(ATL::_U_STRINGorID accel) + { + ATLASSERT(m_hAccel == NULL); + m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), accel.m_lpstr); + return m_hAccel; + } + + HACCEL CreateAcceleratorTable(LPACCEL pAccel, int cEntries) + { + ATLASSERT(m_hAccel == NULL); + ATLASSERT(pAccel != NULL); + m_hAccel = ::CreateAcceleratorTable(pAccel, cEntries); + return m_hAccel; + } + + void DestroyObject() + { + if(m_hAccel != NULL) + { + ::DestroyAcceleratorTable(m_hAccel); + m_hAccel = NULL; + } + } + +// Operations +#ifndef _WIN32_WCE + int CopyAcceleratorTable(LPACCEL lpAccelDst, int cEntries) + { + ATLASSERT(m_hAccel != NULL); + ATLASSERT(lpAccelDst != NULL); + return ::CopyAcceleratorTable(m_hAccel, lpAccelDst, cEntries); + } + + int GetEntriesCount() const + { + ATLASSERT(m_hAccel != NULL); + return ::CopyAcceleratorTable(m_hAccel, NULL, 0); + } +#endif // !_WIN32_WCE + + BOOL TranslateAccelerator(HWND hWnd, LPMSG pMsg) + { + ATLASSERT(m_hAccel != NULL); + ATLASSERT(::IsWindow(hWnd)); + ATLASSERT(pMsg != NULL); + return ::TranslateAccelerator(hWnd, m_hAccel, pMsg); + } +}; + +typedef CAcceleratorT CAcceleratorHandle; +typedef CAcceleratorT CAccelerator; + + +/////////////////////////////////////////////////////////////////////////////// +// CIcon + +template +class CIconT +{ +public: + HICON m_hIcon; + +// Constructor/destructor/operators + CIconT(HICON hIcon = NULL) : m_hIcon(hIcon) + { } + + ~CIconT() + { + if(t_bManaged && m_hIcon != NULL) + ::DestroyIcon(m_hIcon); + } + + CIconT& operator =(HICON hIcon) + { + Attach(hIcon); + return *this; + } + + void Attach(HICON hIcon) + { + if(t_bManaged && m_hIcon != NULL) + ::DestroyIcon(m_hIcon); + m_hIcon = hIcon; + } + + HICON Detach() + { + HICON hIcon = m_hIcon; + m_hIcon = NULL; + return hIcon; + } + + operator HICON() const { return m_hIcon; } + + bool IsNull() const { return m_hIcon == NULL; } + +// Create/destroy methods + HICON LoadIcon(ATL::_U_STRINGorID icon) + { + ATLASSERT(m_hIcon == NULL); + m_hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); + return m_hIcon; + } + + HICON LoadIcon(ATL::_U_STRINGorID icon, int cxDesired, int cyDesired, UINT fuLoad = 0) + { + ATLASSERT(m_hIcon == NULL); + m_hIcon = (HICON) ::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); + return m_hIcon; + } + +#ifndef _WIN32_WCE + HICON LoadOEMIcon(LPCTSTR lpstrIconName) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(IsOEMIcon(lpstrIconName)); + m_hIcon = ::LoadIcon(NULL, lpstrIconName); + return m_hIcon; + } + + HICON CreateIcon(int nWidth, int nHeight, BYTE cPlanes, BYTE cBitsPixel, CONST BYTE* lpbANDbits, CONST BYTE *lpbXORbits) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(lpbANDbits != NULL); + ATLASSERT(lpbXORbits != NULL); + m_hIcon = ::CreateIcon(ModuleHelper::GetResourceInstance(), nWidth, nHeight, cPlanes, cBitsPixel, lpbANDbits, lpbXORbits); + return m_hIcon; + } + + HICON CreateIconFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(pBits != NULL); + m_hIcon = ::CreateIconFromResource(pBits, dwResSize, TRUE, dwVersion); + return m_hIcon; + } + + HICON CreateIconFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(pbBits != NULL); + ATLASSERT(cbBits > 0); + m_hIcon = ::CreateIconFromResourceEx(pbBits, cbBits, TRUE, dwVersion, cxDesired, cyDesired, uFlags); + return m_hIcon; + } +#endif // !_WIN32_WCE + + HICON CreateIconIndirect(PICONINFO pIconInfo) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(pIconInfo != NULL); + m_hIcon = ::CreateIconIndirect(pIconInfo); + return m_hIcon; + } + +#ifndef _WIN32_WCE + HICON ExtractIcon(LPCTSTR lpszExeFileName, UINT nIconIndex) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(lpszExeFileName != NULL); + m_hIcon = ::ExtractIcon(ModuleHelper::GetModuleInstance(), lpszExeFileName, nIconIndex); + return m_hIcon; + } + + HICON ExtractAssociatedIcon(HINSTANCE hInst, LPTSTR lpIconPath, LPWORD lpiIcon) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(lpIconPath != NULL); + ATLASSERT(lpiIcon != NULL); + m_hIcon = ::ExtractAssociatedIcon(hInst, lpIconPath, lpiIcon); + return m_hIcon; + } +#endif // !_WIN32_WCE + + BOOL DestroyIcon() + { + ATLASSERT(m_hIcon != NULL); + BOOL bRet = ::DestroyIcon(m_hIcon); + if(bRet != FALSE) + m_hIcon = NULL; + return bRet; + } + +// Operations +#ifndef _WIN32_WCE + HICON CopyIcon() + { + ATLASSERT(m_hIcon != NULL); + return ::CopyIcon(m_hIcon); + } + + HICON DuplicateIcon() + { + ATLASSERT(m_hIcon != NULL); + return ::DuplicateIcon(NULL, m_hIcon); + } +#endif // !_WIN32_WCE + + BOOL DrawIcon(HDC hDC, int x, int y) + { + ATLASSERT(m_hIcon != NULL); +#ifndef _WIN32_WCE + return ::DrawIcon(hDC, x, y, m_hIcon); +#else // CE specific + return ::DrawIconEx(hDC, x, y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL); +#endif // _WIN32_WCE + } + + BOOL DrawIcon(HDC hDC, POINT pt) + { + ATLASSERT(m_hIcon != NULL); +#ifndef _WIN32_WCE + return ::DrawIcon(hDC, pt.x, pt.y, m_hIcon); +#else // CE specific + return ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL); +#endif // _WIN32_WCE + } + + BOOL DrawIconEx(HDC hDC, int x, int y, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) + { + ATLASSERT(m_hIcon != NULL); + return ::DrawIconEx(hDC, x, y, m_hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); + } + + BOOL DrawIconEx(HDC hDC, POINT pt, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) + { + ATLASSERT(m_hIcon != NULL); + return ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); + } + +#ifndef _WIN32_WCE + BOOL GetIconInfo(PICONINFO pIconInfo) const + { + ATLASSERT(m_hIcon != NULL); + ATLASSERT(pIconInfo != NULL); + return ::GetIconInfo(m_hIcon, pIconInfo); + } + +#if (_WIN32_WINNT >= 0x0600) + BOOL GetIconInfoEx(PICONINFOEX pIconInfo) const + { + ATLASSERT(m_hIcon != NULL); + ATLASSERT(pIconInfo != NULL); + return ::GetIconInfoEx(m_hIcon, pIconInfo); + } +#endif // (_WIN32_WINNT >= 0x0600) + +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) + HRESULT LoadIconMetric(ATL::_U_STRINGorID icon, int lims) + { + ATLASSERT(m_hIcon == NULL); + USES_CONVERSION; + return ::LoadIconMetric(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), lims, &m_hIcon); + } + + HRESULT LoadIconWithScaleDown(ATL::_U_STRINGorID icon, int cx, int cy) + { + ATLASSERT(m_hIcon == NULL); + USES_CONVERSION; + return ::LoadIconWithScaleDown(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), cx, cy, &m_hIcon); + } + + HRESULT LoadOEMIconMetric(LPCTSTR lpstrIconName, int lims) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(IsOEMIcon(lpstrIconName)); + return ::LoadIconMetric(NULL, (LPCWSTR)lpstrIconName, lims, &m_hIcon); + } + + HRESULT LoadOEMIconWithScaleDown(LPCTSTR lpstrIconName, int cx, int cy) + { + ATLASSERT(m_hIcon == NULL); + ATLASSERT(IsOEMIcon(lpstrIconName)); + USES_CONVERSION; + return ::LoadIconWithScaleDown(NULL, (LPCWSTR)lpstrIconName, cx, cy, &m_hIcon); + } +#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) +#endif // !_WIN32_WCE + + // Helper +#ifndef _WIN32_WCE + static bool IsOEMIcon(LPCTSTR lpstrIconName) + { +#if (WINVER >= 0x0600) + return (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION || + lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO || + lpstrIconName == IDI_SHIELD); +#else // !(WINVER >= 0x0600) + return (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION || + lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO); +#endif // !(WINVER >= 0x0600) + } +#endif // !_WIN32_WCE +}; + +typedef CIconT CIconHandle; +typedef CIconT CIcon; + + +/////////////////////////////////////////////////////////////////////////////// +// CCursor + +// protect template member from a winuser.h macro +#ifdef CopyCursor + #undef CopyCursor +#endif + +template +class CCursorT +{ +public: + HCURSOR m_hCursor; + +// Constructor/destructor/operators + CCursorT(HCURSOR hCursor = NULL) : m_hCursor(hCursor) + { } + + ~CCursorT() + { + if(t_bManaged && m_hCursor != NULL) + DestroyCursor(); + } + + CCursorT& operator =(HCURSOR hCursor) + { + Attach(hCursor); + return *this; + } + + void Attach(HCURSOR hCursor) + { + if(t_bManaged && m_hCursor != NULL) + DestroyCursor(); + m_hCursor = hCursor; + } + + HCURSOR Detach() + { + HCURSOR hCursor = m_hCursor; + m_hCursor = NULL; + return hCursor; + } + + operator HCURSOR() const { return m_hCursor; } + + bool IsNull() const { return m_hCursor == NULL; } + +// Create/destroy methods + HCURSOR LoadCursor(ATL::_U_STRINGorID cursor) + { + ATLASSERT(m_hCursor == NULL); + m_hCursor = ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr); + return m_hCursor; + } + + HCURSOR LoadSysCursor(LPCTSTR lpstrCursorName) + { + ATLASSERT(m_hCursor == NULL); +#if (WINVER >= 0x0500) + ATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT || + lpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE || + lpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW || + lpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL || + lpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP || + lpstrCursorName == IDC_HAND); +#else // !(WINVER >= 0x0500) + ATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT || + lpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE || + lpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW || + lpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL || + lpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP); +#endif // !(WINVER >= 0x0500) + m_hCursor = ::LoadCursor(NULL, lpstrCursorName); + return m_hCursor; + } + + // deprecated + HCURSOR LoadOEMCursor(LPCTSTR lpstrCursorName) + { + return LoadSysCursor(lpstrCursorName); + } + + HCURSOR LoadCursor(ATL::_U_STRINGorID cursor, int cxDesired, int cyDesired, UINT fuLoad = 0) + { + ATLASSERT(m_hCursor == NULL); + m_hCursor = (HCURSOR) ::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); + return m_hCursor; + } + +#ifndef _WIN32_WCE + HCURSOR LoadCursorFromFile(LPCTSTR pstrFilename) + { + ATLASSERT(m_hCursor == NULL); + ATLASSERT(pstrFilename != NULL); + m_hCursor = ::LoadCursorFromFile(pstrFilename); + return m_hCursor; + } +#endif // !_WIN32_WCE + +#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + HCURSOR CreateCursor(int xHotSpot, int yHotSpot, int nWidth, int nHeight, CONST VOID *pvANDPlane, CONST VOID *pvXORPlane) + { + ATLASSERT(m_hCursor == NULL); + m_hCursor = ::CreateCursor(ModuleHelper::GetResourceInstance(), xHotSpot, yHotSpot, nWidth, nHeight, pvANDPlane, pvXORPlane); + return m_hCursor; + } +#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + +#ifndef _WIN32_WCE + HCURSOR CreateCursorFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000) + { + ATLASSERT(m_hCursor == NULL); + ATLASSERT(pBits != NULL); + m_hCursor = (HCURSOR)::CreateIconFromResource(pBits, dwResSize, FALSE, dwVersion); + return m_hCursor; + } + + HCURSOR CreateCursorFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR) + { + ATLASSERT(m_hCursor == NULL); + ATLASSERT(pbBits != NULL); + ATLASSERT(cbBits > 0); + m_hCursor = (HCURSOR)::CreateIconFromResourceEx(pbBits, cbBits, FALSE, dwVersion, cxDesired, cyDesired, uFlags); + return m_hCursor; + } +#endif // !_WIN32_WCE + + BOOL DestroyCursor() + { + ATLASSERT(m_hCursor != NULL); +#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) + BOOL bRet = ::DestroyCursor(m_hCursor); + if(bRet != FALSE) + m_hCursor = NULL; + return bRet; +#else // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))) + ATLTRACE2(atlTraceUI, 0, _T("Warning: This version of Windows CE does not have ::DestroyCursor()\n")); + return FALSE; +#endif // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))) + } + +// Operations +#ifndef _WIN32_WCE + HCURSOR CopyCursor() + { + ATLASSERT(m_hCursor != NULL); + return (HCURSOR)::CopyIcon((HICON)m_hCursor); + } +#endif // !_WIN32_WCE + +#if (WINVER >= 0x0500) && !defined(_WIN32_WCE) + BOOL GetCursorInfo(LPCURSORINFO pCursorInfo) + { + ATLASSERT(m_hCursor != NULL); + ATLASSERT(pCursorInfo != NULL); + return ::GetCursorInfo(pCursorInfo); + } +#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) +}; + +typedef CCursorT CCursorHandle; +typedef CCursorT CCursor; + + +/////////////////////////////////////////////////////////////////////////////// +// CResource - Wraps a generic Windows resource. +// Use it with custom resource types other than the +// standard RT_CURSOR, RT_BITMAP, etc. + +class CResource +{ +public: + HGLOBAL m_hGlobal; + HRSRC m_hResource; + +// Constructor/destructor + CResource() : m_hGlobal(NULL), m_hResource(NULL) + { } + + ~CResource() + { + Release(); + } + +// Load methods + bool Load(ATL::_U_STRINGorID Type, ATL::_U_STRINGorID ID) + { + ATLASSERT(m_hResource == NULL); + ATLASSERT(m_hGlobal == NULL); + + m_hResource = ::FindResource(ModuleHelper::GetResourceInstance(), ID.m_lpstr, Type.m_lpstr); + if(m_hResource == NULL) + return false; + + m_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource); + if(m_hGlobal == NULL) + { + m_hResource = NULL; + return false; + } + + return true; + } + +#ifndef _WIN32_WCE + bool LoadEx(ATL::_U_STRINGorID Type, ATL::_U_STRINGorID ID, WORD wLanguage) + { + ATLASSERT(m_hResource == NULL); + ATLASSERT(m_hGlobal == NULL); + + m_hResource = ::FindResourceEx(ModuleHelper::GetResourceInstance(), ID.m_lpstr, Type.m_lpstr, wLanguage); + if(m_hResource == NULL) + return false; + + m_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource); + if(m_hGlobal == NULL) + { + m_hResource = NULL; + return false; + } + + return true; + } +#endif // !_WIN32_WCE + +// Misc. operations + DWORD GetSize() const + { + ATLASSERT(m_hResource != NULL); + return ::SizeofResource(ModuleHelper::GetResourceInstance(), m_hResource); + } + + LPVOID Lock() + { + ATLASSERT(m_hResource != NULL); + ATLASSERT(m_hGlobal != NULL); + LPVOID pVoid = ::LockResource(m_hGlobal); + ATLASSERT(pVoid != NULL); + return pVoid; + } + + void Release() + { + if(m_hGlobal != NULL) + { + FreeResource(m_hGlobal); + m_hGlobal = NULL; + m_hResource = NULL; + } + } +}; + +}; // namespace WTL + +#endif // __ATLUSER_H__ diff --git a/wtl/wtl/include/atlwince.h b/wtl/wtl/include/atlwince.h new file mode 100644 index 00000000..5502d2ec --- /dev/null +++ b/wtl/wtl/include/atlwince.h @@ -0,0 +1,3010 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLWINCE_H__ +#define __ATLWINCE_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlwince.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error atlwince.h requires atlwin.h to be included first +#endif + +#ifndef _WIN32_WCE + #error atlwince.h compiles under Windows CE only +#elif (_WIN32_WCE < 300) + #error atlwince.h requires Windows CE 3.0 or higher. +#endif + +#if defined(WIN32_PLATFORM_WFSP) && _MSC_VER < 1400 // EVC compiling SmartPhone code + #if (WIN32_PLATFORM_WFSP < 200) + #error atlwince.h requires Smartphone 2003 or higher + #endif +#endif // WIN32_PLATFORM_WFSP + +#if defined(WIN32_PLATFORM_PSPC) && _MSC_VER < 1400 // EVC compiling Pocket PC code + #if (WIN32_PLATFORM_PSPC < 310) + #error atlwince.h requires Pocket PC 2002 or higher + #endif +#endif // WIN32_PLATFORM_PSPC + +#if !defined(_AYGSHELL_H_) && !defined(__AYGSHELL_H__) + #error atlwince.h requires aygshell.h to be included first +#else + #if defined(WIN32_PLATFORM_WFSP) && !defined(_TPCSHELL_H_) + #error SmartPhone dialog classes require tpcshell.h to be included first + #endif +#endif + +#if (_MSC_VER >= 1400) // VS2005 + #include + #define _WTL_CE_DRA +#endif // (_MSC_VER >= 1400) + +#if !defined(_WTL_CE_NO_DIALOGS) && !defined(__ATLFRAME_H__) + #error Orientation aware dialog classes require atlframe.h to be included first +#endif + +#if !defined(_WTL_CE_NO_APPWINDOW) && !defined(__ATLFRAME_H__) + #error Application window class require atlframe.h to be included first +#endif + +#if !defined(_WTL_CE_NO_ZOOMSCROLL) && !defined(__ATLSCRL_H__) + #error ZoomScroll implementation requires atlscrl.h to be included first +#endif + +#if !defined(_WTL_CE_NO_ZOOMSCROLL) + #if !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES))) + #error ZoomScroll requires _WTL_NO_WTYPES not to be defined and either atlmisc.h or atltypes.h to be included first + #endif // !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES))) +#endif // !defined(_WTL_CE_NO_ZOOMSCROLL) + +#if !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC) + #define _WTL_CE_NO_CONTROLS +#endif // !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC) + +#ifndef _WTL_CE_NO_CONTROLS + #ifndef __ATLCTRLS_H__ + #error The PPC/SmartPhone controls classes require atlctrls.h to be included first + #endif + + #include + #pragma comment(lib, "htmlview.lib") + + #include + #pragma comment(lib, "voicectl.lib") + + #ifdef WIN32_PLATFORM_PSPC + #include + #pragma comment(lib, "richink.lib") + + #include + #pragma comment(lib, "inkx.lib") + + #include + #pragma comment(lib, "doclist.lib") + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// CStdDialogBase : Standard PPC/SmartPhone dialog base class +// CStdDialogImplBase - Base implementation of standard dialog +// CStdDialogImpl : Standard dialog implementation +// CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog +// CStdAxDialogImpl : Standard AxDialog implementation +// CStdSimpleDialog : Standard simple dialog +// CStdDialogResizeImplBase - Base implementation of orientation resizing standard dialog +// CStdDialogResizeImpl : Orientation resizing standard dialog implementation +// CStdAxDialogResizeImpl - implementation of orientation resizing standard AxDialog +// CStdSimpleDialogResizeImpl : Standard resizing simple dialog implementation +// CStdOrientedDialogBase - Oriented PPC standard dialog base class +// CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation +// CStdOrientedDialogImpl : Oriented PPC standard dialog implementation +// CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation +// CStdSimpleOrientedDialog : Standard simple orientable dialog +// +// CAppInfoBase : Helper for application state save/restore to registry +// CAppInfoT : CAppInfoBase constructed from a CAppWindow +// CAppWindowBase : Base class for PPC/SmartPhone well-behaved application window or dialog +// CAppWindow : PPC/SmartPhone well-behaved application window class +// CAppDialog : PPC/SmartPhone well-behaved application dialog class +// CAppStdDialogImplBase - Base implementation of standard application dialogs +// CAppStdDialogImpl : Implementation of standard application dialog +// CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog +// CAppStdAxDialogImpl - Implementation of standard application AxDialog +// CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog +// CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog +// CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog +// +// CFullScreenFrame : Full screen frame class +// +// CZoomScrollImpl : WinCE zooming implementation +// +// CBottomTabViewImpl - CBottomTabView +// CHtmlCtrlT - CHtmlCtrl +// CRichInkCtrlT - CRichInkCtrl +// CInkXCtrlT - CInkXCtrl +// CVoiceRecorderCtrlT - CVoiceRecorderCtrl +// CDocListCtrlT - CDocListCtrl +// CCapEditT - CCapEdit +// CTTStaticT - CTTStatic +// CTTButtonT - CTTButton +// +// CSpinCtrlT - CSpinCtrl : SmartPhone specific UpDown control +// CSpinned : SmartPhone association of control and Spin +// CSpinListBox : SmartPhone spinned ListBox control +// CExpandListBox : SmartPhone expandable ListBox control +// CExpandEdit : SmartPhone expandable Edit control +// CExpandCapEdit : SmartPhone expandable CapEdit control +// +// Global functions: +// AtlCreateMenuBar() +// AtlCreateEmptyMenuBar() +// AtlIsEditFocus() +// AtlActivateBackKey() + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// MenuBar creation functions for property sheets and dialogs +// Frame windows use CreateSimpleCEMenuBar + +inline HWND AtlCreateMenuBar(SHMENUBARINFO& mbi) +{ + ATLASSERT(::IsWindow(mbi.hwndParent)); + ATLVERIFY(::SHCreateMenuBar(&mbi) != FALSE); + return mbi.hwndMB; +}; + +inline HWND AtlCreateMenuBar(HWND hWnd, UINT nToolBarId = ATL_IDW_TOOLBAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0, COLORREF clrBk = 0) +{ + SHMENUBARINFO mbi = { sizeof(mbi), hWnd, dwFlags, nToolBarId, ModuleHelper::GetResourceInstance(), nBmpId, cBmpImages, 0, clrBk }; + return AtlCreateMenuBar(mbi); +} + +inline HWND AtlCreateEmptyMenuBar(HWND hWnd, bool bSip = true) +{ + SHMENUBARINFO embi = { sizeof(SHMENUBARINFO), hWnd, SHCMBF_EMPTYBAR }; + if (!bSip) + embi.dwFlags |= SHCMBF_HIDESIPBUTTON; + + return AtlCreateMenuBar(embi); +} + +/////////////////////////////////////////////////////////////////////////////// +// Helper functions for SmartPhone back key handling + +inline bool AtlIsEditFocus() +{ + ATL::CWindow wCtrl = GetFocus(); + if (wCtrl.IsWindow()) + { + TCHAR szClassName[8] = {0}; + ATLVERIFY(::GetClassName(wCtrl.m_hWnd, szClassName, 8)); + return !_tcscmp(szClassName, _T("Edit")) || !_tcscmp(szClassName, WC_CAPEDIT); + } + return false; +} + +#if defined WIN32_PLATFORM_WFSP +inline void AtlActivateBackKey(HWND hMenuBar) +{ + ATLASSERT(::IsWindow(hMenuBar)); + ::SendMessage(hMenuBar, SHCMBM_OVERRIDEKEY, VK_TBACK, + MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY)); +} +#endif // WIN32_PLATFORM_WFSP + +// --- Standard PPC/SmartPhone dialogs --- + +#ifndef _WTL_CE_NO_DIALOGS + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogBase - base class for standard PPC/SmartPhone dialogs + +#define WTL_STD_SHIDIF SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN +#define WTL_SP_SHIDIF SHIDIF_SIZEDLGFULLSCREEN + +// Title setting macros +#define WTL_DLG_TITLEHEIGHT(iHeight) static const int GetTitleHeight(){return iHeight;} +#define WTL_DLG_NOTITLE WTL_DLG_TITLEHEIGHT(0) + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogBase - Base class for standard PPC/SmartPhone dialog + +template +class CStdDialogBase +{ +public: +#ifdef WIN32_PLATFORM_PSPC +// Pocket PC only Dialog title handling + const int nTitleHeight; + + CStdDialogBase() : nTitleHeight(T::GetTitleHeight()) + { } + +// Overloads + BOOL GetClientRect(LPRECT lpRect) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + BOOL bRes = ::GetClientRect(pT->m_hWnd, lpRect); + lpRect->top += nTitleHeight; + return bRes; + } + + BOOL SetWindowText(LPCTSTR lpszString) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + BOOL bRes = ::SetWindowText(pT->m_hWnd, lpszString); + if (nTitleHeight != 0) + pT->DoPaintTitle(); + return bRes; + } + +// Overrideables + static const int GetTitleHeight() + { + #ifdef _WTL_CE_DRA + return DRA::SCALEY(24); + #else // !_WTL_CE_DRA + CWindowDC dc(NULL); + return dc.GetDeviceCaps(LOGPIXELSY) >> 2; // LOGPIXELSY * 24 / 96, + #endif // !_WTL_CE_DRA + } + + // Title painting + bool DoPaintTitle() + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + TCHAR sTitle[48]; + + // Preparation + CPaintDC dc(pT->m_hWnd); + CFont fontTitle = AtlCreateBoldFont(); + CFontHandle fontOld = dc.SelectFont(fontTitle); + dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHT)); + int nLen = pT->GetWindowText(sTitle, 48); + int nWidth = dc.GetDeviceCaps(HORZRES); + + // Display title text + RECT rTitle = { 0, 0, nWidth, nTitleHeight }; + dc.FillRect(&rTitle, COLOR_3DHIGHLIGHT); + #ifdef _WTL_CE_DRA + rTitle.left = DRA::SCALEX(8); + #else // !_WTL_CE_DRA + rTitle.left = nTitleHeight / 3; // 8 == 24 / 3 + #endif // !_WTL_CE_DRA + dc.DrawText(sTitle, nLen, &rTitle, DT_VCENTER | DT_SINGLELINE); + dc.SelectFont(fontOld); + + // Draw bottom line, 2 pixels thick if HI_RES_AWARE + CPenHandle penOld = dc.SelectStockPen(BLACK_PEN); + POINT line[4] = {{0, nTitleHeight}, {nWidth, nTitleHeight}, {0, nTitleHeight - 1}, {nWidth, nTitleHeight - 1}}; + + #ifdef _WTL_CE_DRA + int nSeg = DRA::SCALEY(1); + #else // !_WTL_CE_DRA + int nSeg = nTitleHeight / 24; + #endif // !_WTL_CE_DRA + + dc.Polyline(line, nSeg <= 2 ? nSeg * 2 : 4); + dc.SelectPen(penOld); + + return false; + } + + // Title preparation: move the dialog controls down to make room for title + void DialogTitleInit() + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + + ATL::CWindow wCtl = pT->GetWindow(GW_CHILD); + while (wCtl.IsWindow()) + { + RECT rCtl = { 0 }; + wCtl.GetWindowRect(&rCtl); + ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rCtl, 2); + ::OffsetRect(&rCtl, 0, nTitleHeight); + wCtl.MoveWindow(&rCtl, FALSE); + wCtl = wCtl.GetWindow(GW_HWNDNEXT); + } + } + + // SIP management + void DoSipInfo() + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + + SIPINFO si = {sizeof(SIPINFO)}; + SipGetInfo(&si); + if ((si.fdwFlags & SIPF_ON) ^ SIPF_ON) + si.rcVisibleDesktop.bottom = si.rcSipRect.bottom; + pT->MoveWindow(&si.rcVisibleDesktop, FALSE); + } + +// Title painting handler + LRESULT OnPaintTitle(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + return bHandled = nTitleHeight ? pT->DoPaintTitle() : FALSE; + } + +// SIP handler + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + if (wParam == SPI_SETSIPINFO) + { + pT->DoSipInfo(); + return TRUE; + } + return bHandled = FALSE; + } + +#elif defined WIN32_PLATFORM_WFSP +// SmartPhone VK_TBACK key standard management + LRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + const UINT uModif = (UINT)LOWORD(lParam); + const UINT uVirtKey = (UINT)HIWORD(lParam); + + if(uVirtKey == VK_TBACK) + if (AtlIsEditFocus()) + ::SHSendBackToFocusWindow(uMsg, wParam, lParam); + else if (uModif & MOD_KEYUP) + pT->StdCloseDialog(IDCANCEL); + return 1; + } + + // SmartPhone MenuBar and VK_TBACK key initialization + void StdSPInit() + { + T* pT = static_cast(this); + HWND hMenuBar = ::SHFindMenuBar(pT->m_hWnd); + + if (!hMenuBar && (t_shidiFlags & SHIDIF_DONEBUTTON)) + hMenuBar = CreateMenuBar(ATL_IDM_MENU_DONE); + + if(hMenuBar != NULL) + AtlActivateBackKey(hMenuBar); + } + + void SetStaticBold() + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + + CFontHandle fontBold = AtlCreateBoldFont(pT->GetFont()); + + ATL::CWindow wCtl = pT->GetWindow(GW_CHILD); + + while (wCtl.IsWindow()) + { + if ((short int)wCtl.GetDlgCtrlID() == IDC_STATIC) + wCtl.SetFont(fontBold); + wCtl = wCtl.GetWindow(GW_HWNDNEXT); + } + } +#endif // WIN32_PLATFORM_WFSP + +// Platform dependant initialization + void StdPlatformInit() + { + T* pT = static_cast(this); +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title initialization + if (nTitleHeight != 0) + pT->DialogTitleInit(); +#elif defined(WIN32_PLATFORM_WFSP) + pT->StdSPInit(); + SetStaticBold(); +#endif // WIN32_PLATFORM_WFSP + } + + // Menu bar creation + HWND CreateMenuBar(UINT uiMB = T::IDD, int nBmpImages = 0) + { + T* pT = static_cast(this); + return AtlCreateMenuBar(pT->m_hWnd, uiMB, 0, nBmpImages ? uiMB : 0, nBmpImages); + } + + // Dialog closing + void StdCloseDialog(WORD wID) + { + T* pT = static_cast(this); + if (t_bModal) + ::EndDialog(pT->m_hWnd, wID); + else + pT->DestroyWindow(); + } + + // Shell dialog layout initialization + void StdShidInit() + { + T* pT = static_cast(this); + SHINITDLGINFO shidi = { SHIDIM_FLAGS, pT->m_hWnd, t_shidiFlags }; + ::SHInitDialog(&shidi); + } + +// IDC_INFOSTATIC background setting + LRESULT OnColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + if (::GetDlgCtrlID((HWND)lParam) == IDC_INFOSTATIC) + { + ::SetBkMode((HDC)wParam, TRANSPARENT); + return (LRESULT)::GetSysColorBrush(COLOR_INFOBK); + } + return bHandled = FALSE; + } + +// Menu dialog ending + LRESULT OnMenuClose(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->StdCloseDialog((WORD)(wID - ID_MENU_OK + IDOK)); + return 0; + } + +// Standard dialog ending: may be used with any command + LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->StdCloseDialog(wID); + return 0; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogImplBase - Base implementation of standard PPC/SmartPhone dialog + +template > +class ATL_NO_VTABLE CStdDialogImplBase : + public TBase, + public CStdDialogBase +{ +public: +#ifdef WIN32_PLATFORM_PSPC + BOOL GetClientRect(LPRECT lpRect) + { + return CStdDialogBase::GetClientRect(lpRect); + } + + BOOL SetWindowText(LPCTSTR lpszString) + { + return CStdDialogBase::SetWindowText(lpszString); + } +#endif + + BEGIN_MSG_MAP(CStdDialogImplBase) +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) +#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#endif + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _DEBUG + T* pT = static_cast(this); + ATLASSERT(t_bModal == pT->m_bModal); +#endif + StdPlatformInit(); + StdShidInit(); + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogImpl - implementation of standard PPC/SmartPhone dialog + +template +class ATL_NO_VTABLE CStdDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal> +{}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog + +#if defined __ATLDLGS_H__ + +template +class ATL_NO_VTABLE CStdIndirectDialogImpl : + public CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl > +{ +public: + typedef CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl > _baseClass; + typedef CStdDialogImpl _baseStd; + + INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL) + { + ATLASSERT(t_bModal); + + if (!m_Template.IsValid()) + CreateTemplate(); + + if (m_Template.IsTemplateEx()) + { + if (m_Template.GetTemplateExPtr()->style & DS_CENTER) + { + ATLASSERT(m_Template.GetTemplateExPtr()->style ^ WS_CHILD); + GetTemplateExPtr()->style |= WS_POPUP; + } + } + else + { + if (m_Template.GetTemplatePtr()->style & DS_CENTER) + { + ATLASSERT(m_Template.GetTemplatePtr()->style ^ WS_CHILD); + m_Template.GetTemplatePtr()->style |= WS_POPUP; + } + } + + return _baseClass::DoModal(hWndParent, dwInitParam); + } + + HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL) + { + ATLASSERT(!t_bModal); + + if (!m_Template.IsValid()) + CreateTemplate(); + + if (m_Template.IsTemplateEx()) + { + if (GetTemplateExPtr()->style & DS_CENTER) + { + ATLASSERT(GetTemplateExPtr()->style ^ WS_CHILD); + GetTemplateExPtr()->style |= WS_POPUP; + } + } + else + { + if (GetTemplatePtr()->style & DS_CENTER) + { + ATLASSERT(GetTemplatePtr()->style ^ WS_CHILD); + GetTemplatePtr()->style |= WS_POPUP; + } + } + + return _baseClass::Create(hWndParent, dwInitParam); + } + + BEGIN_MSG_MAP(CStdIndirectDialogImpl) + CHAIN_MSG_MAP(_baseStd) + END_MSG_MAP() + +}; + +#endif // defined __ATLDLGS_H__ + +#ifndef _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdAxDialogImpl - implementation of standard PPC/SmartPhone AxDialog + +template +class ATL_NO_VTABLE CStdAxDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl< T > > +{}; +#endif // _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdSimpleDialog - standard PPC/SmartPhone simple dialog with SHIDIF_xxx flags + +template +class CStdSimpleDialog : + public ATL::CSimpleDialog, + public CStdDialogBase, t_shidiFlags> +{ +public: + typedef CStdDialogBase, t_shidiFlags> baseClass; + +#ifdef WIN32_PLATFORM_PSPC + BOOL GetClientRect(LPRECT lpRect) + { + return baseClass::GetClientRect(lpRect); + } + + BOOL SetWindowText(LPCTSTR lpszString) + { + return baseClass::SetWindowText(lpszString); + } +#endif + + BEGIN_MSG_MAP(CStdSimpleDialog) +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) +#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#endif + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + StdPlatformInit(); + StdShidInit(); + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogResizeImplBase - Base implementation of orientation resizing standard PPC/SmartPhone dialog + +template > +class ATL_NO_VTABLE CStdDialogResizeImplBase : + public CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>, + public CDialogResize +{ +public: + // Note: BEGIN_DLGRESIZE_MAP is required in the derived class. + + BEGIN_MSG_MAP(CStdResizeDialogImplBase) +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) +#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#endif + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + CHAIN_MSG_MAP(CDialogResize< T >) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifdef _DEBUG + T* pT = static_cast(this); + ATLASSERT(t_bModal == pT->m_bModal); +#endif + StdPlatformInit(); + DlgResize_Init(FALSE); + StdShidInit(); + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone dialog + +template +class ATL_NO_VTABLE CStdDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal> +{}; + +#ifndef _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdAxDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone AxDialog + +template +class ATL_NO_VTABLE CStdAxDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl > +{}; +#endif // _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdSimpleDialogResizeImpl - implementation of standard resizing simple dialog with SHIDIF_xxx flags + +// Usage: +// class CMyDlg : public CStdSimpleDialogResize +// { +// public: +// BEGIN_DLGRESIZE_MAP(CMyDlg) +// ... +// END_DLGRESIZE_MAP() +// }; + +template +class ATL_NO_VTABLE CStdSimpleDialogResizeImpl : + public CStdSimpleDialog, + public CDialogResize< T > +{ +public: + typedef CStdSimpleDialog::baseClass baseClass; + + BEGIN_MSG_MAP(CStdSimpleDialogResizeImpl) +#ifdef WIN32_PLATFORM_PSPC // Pocket PC title + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) +#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#endif + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + CHAIN_MSG_MAP(CDialogResize< T >) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + StdPlatformInit(); + DlgResize_Init(FALSE); + StdShidInit(); + return bHandled = FALSE; + } +}; + +#if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC) + +/////////////////////////////////////////////////////////////////////////////// +// CStdOrientedDialogBase - Oriented PPC standard dialog base class + +template +class CStdOrientedDialogBase +{ +public: +// Operation + BOOL SetOrientation(DRA::DisplayMode mode) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + ATLASSERT(mode == DRA::GetDisplayMode()); + + // Derived dialog must enumerate TWO dialog templates with the same control ids and types ie: + // enum { IDD = IDD_MYDLG, IDD_LANDSCAPE = IDD_MYDLG_L }; + UINT iResource = (mode == DRA::Landscape)? T::IDD_LANDSCAPE : T::IDD; + + BOOL bRes = DRA::RelayoutDialog(ModuleHelper::GetResourceInstance(), pT->m_hWnd, MAKEINTRESOURCE(iResource)); + pT->OnOrientation(mode); + return bRes; + } + +// Override + void OnOrientation(DRA::DisplayMode /*mode*/) + {} + +// Message handlers + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + if (wParam == SETTINGCHANGE_RESET) + { + SetOrientation(DRA::GetDisplayMode()); + pT->StdPlatformInit(); + pT->StdShidInit(); + } + else if (wParam == SPI_SETSIPINFO) + { + pT->DoSipInfo(); + return TRUE; + } + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation + +template > +class ATL_NO_VTABLE CStdOrientedDialogImplBase : + public CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>, + public CStdOrientedDialogBase +{ +public: + BEGIN_MSG_MAP(CStdOrientedDialogImpl) + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_SETTINGCHANGE, CStdOrientedDialogBase::OnSettingChange) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); +#ifdef _DEBUG + ATLASSERT(t_bModal == pT->m_bModal); +#endif + if (DRA::GetDisplayMode() == DRA::Landscape) + SetOrientation(DRA::Landscape); + pT->StdPlatformInit(); + pT->StdShidInit(); + return bHandled = FALSE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CStdOrientedDialogImpl - Oriented PPC standard dialog implementation + +template +class ATL_NO_VTABLE CStdOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal> +{}; + +#ifndef _ATL_NO_HOSTING +/////////////////////////////////////////////////////////////////////////////// +// CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation + +template +class ATL_NO_VTABLE CStdAxOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl > +{}; +#endif // _ATL_NO_HOSTING + +/////////////////////////////////////////////////////////////////////////////// +// CStdSimpleOrientedDialog - Standard simple orientable dialog + +template +class CStdSimpleOrientedDialog : + public CStdSimpleDialog, + public CStdOrientedDialogBase > +{ +public: + typedef CStdSimpleDialog::baseClass baseClass; + typedef CStdOrientedDialogBase > baseOriented; + + enum {IDD = t_wDlgTemplateID, IDD_LANDSCAPE = t_wDlgLandscapeID}; + + BEGIN_MSG_MAP(CStdSimpleDialog) + MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) + MESSAGE_HANDLER(WM_SETTINGCHANGE, baseOriented::OnSettingChange) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd) + COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) + END_MSG_MAP() + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if (DRA::GetDisplayMode() == DRA::Landscape) + SetOrientation(DRA::Landscape); + StdPlatformInit(); + StdShidInit(); + return bHandled = FALSE; + } +}; + +#endif // _WTL_CE_DRA + + +#endif // _WTL_CE_NO_DIALOGS + + +// --- PPC/SmartPhone application window and helpers --- + +#ifndef _WTL_CE_NO_APPWINDOW + +/////////////////////////////////////////////////////////////////////////////// +// CAppInfoBase - Helper for application state save/restore to registry + +class CAppInfoBase +{ +public: + ATL::CRegKey m_Key; + + CAppInfoBase(ATL::_U_STRINGorID sAppKey) + { + m_Key.Create(HKEY_CURRENT_USER, sAppKey.m_lpstr); + ATLASSERT(m_Key.m_hKey); + } + + template + LONG Save(V& val, ATL::_U_STRINGorID sName) + { + return ::RegSetValueEx(m_Key, sName.m_lpstr, 0, REG_BINARY, (LPBYTE)&val, sizeof(V)); + } + + template + LONG Save(int nb, V& val0, ATL::_U_STRINGorID sName) + { + return ::RegSetValueEx(m_Key, sName.m_lpstr, 0, REG_BINARY, (LPBYTE)&val0, nb * sizeof(V)); + } + + template + LONG Restore(V& val, ATL::_U_STRINGorID sName) + { + DWORD valtype; + DWORD bufSize = sizeof(V); + return ::RegQueryValueEx(m_Key, sName.m_lpstr, 0, &valtype, (LPBYTE)&val, &bufSize); + } + + template + LONG Restore(int nb, V& val0, ATL::_U_STRINGorID sName) + { + DWORD valtype; + DWORD bufSize = nb * sizeof(V); + return ::RegQueryValueEx(m_Key, sName.m_lpstr, 0, &valtype, (LPBYTE)&val0, &bufSize); + } + +#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) +#if (_ATL_VER < 0x0800) + LONG Save(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName) + { + return m_Key.SetValue(sval, sName.m_lpstr); + } + + LONG Restore(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName) + { + DWORD size = MAX_PATH; + LONG res = m_Key.QueryValue(sval.GetBuffer(size), sName.m_lpstr, &size); + sval.ReleaseBuffer(); + return res; + } +#else // !(_ATL_VER < 0x0800) + LONG Save(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName) + { + return m_Key.SetStringValue(sName.m_lpstr, sval); + } + + LONG Restore(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName) + { + DWORD size = MAX_PATH; + LONG res = m_Key.QueryStringValue(sName.m_lpstr, sval.GetBuffer(size), &size); + sval.ReleaseBuffer(); + return res; + } +#endif // !(_ATL_VER < 0x0800) +#else + #pragma message("Warning: CAppInfoBase compiles without CString support. Do not use CString in Save or Restore.") +#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) + +#if (_ATL_VER < 0x0800) + LONG Save(LPCTSTR sval, ATL::_U_STRINGorID sName) + { + return m_Key.SetValue(sval, sName.m_lpstr); + } + + LONG Restore(LPTSTR sval, ATL::_U_STRINGorID sName, DWORD *plength) + { + return m_Key.QueryValue(sval, sName.m_lpstr, plength); + } +#else // !(_ATL_VER < 0x0800) + LONG Save(LPCTSTR sval, ATL::_U_STRINGorID sName) + { + return m_Key.SetStringValue(sName.m_lpstr, sval); + } + + LONG Restore(LPTSTR sval, ATL::_U_STRINGorID sName, DWORD *plength) + { + return m_Key.QueryStringValue(sName.m_lpstr, sval, plength); + } +#endif // !(_ATL_VER < 0x0800) + + LONG Delete(ATL::_U_STRINGorID sName) + { + return m_Key.DeleteValue(sName.m_lpstr); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAppInfoT - CAppInfoBase constructed from a class with T::GetAppKey() + +// Macro for declaring AppKey +#define DECLARE_APPKEY(uAppKey) \ + static LPCTSTR GetAppKey() \ + { \ + static LPCTSTR sAppKey = ATL::_U_STRINGorID(uAppKey).m_lpstr; \ + return sAppKey; \ + } + +template +class CAppInfoT : public CAppInfoBase +{ +public: + CAppInfoT() : CAppInfoBase(T::GetAppKey()){} +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAppWindowBase - Base class for PPC/SmartPhone "well-behaved" application window or dialog + +// Macros for declaring frame WNDCLASS and AppKey +#define DECLARE_APP_FRAME_CLASS(WndClassName, uCommonResourceID, uAppKey) \ + DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ + DECLARE_APPKEY(uAppKey) + +#define DECLARE_APP_FRAME_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd, uAppKey) \ + DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ + DECLARE_APPKEY(uAppKey) + +template +class CAppWindowBase +{ +public: + typedef class CAppInfoT< T > CAppInfo; + +#ifndef WIN32_PLATFORM_WFSP + SHACTIVATEINFO m_sai; // NoOp on SmartPhones +#endif // WIN32_PLATFORM_WFSP + + bool m_bHibernate; + + CAppWindowBase< T >() : m_bHibernate(false) + { +#ifndef WIN32_PLATFORM_WFSP + SHACTIVATEINFO sai = { sizeof(SHACTIVATEINFO) }; + m_sai = sai; +#endif // WIN32_PLATFORM_WFSP + }; + + // Same as WTL 7.1 AppWizard generated ActivatePreviousInstance + SendMessage WM_COPYDATA + static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine, bool bDialog) + { + // requires T does DECLARE_APP_FRAME_CLASS, DECLARE_APP_FRAME_CLASS_EX or DECLARE_APP_DLG_CLASS + CFrameWndClassInfo& classInfo = T::GetWndClassInfo(); + + ATLVERIFY(::LoadString(hInstance, classInfo.m_uCommonResourceID, classInfo.m_szAutoName, sizeof(classInfo.m_szAutoName)/sizeof(classInfo.m_szAutoName[0])) != 0); + + classInfo.m_wc.lpszClassName = classInfo.m_szAutoName; + + const TCHAR* pszClass = classInfo.m_wc.lpszClassName; + + if(NULL == pszClass || '\0' == *pszClass) + { + return E_FAIL; + } + + const DWORD dRetryInterval = 100; + const int iMaxRetries = 25; + + for(int i = 0; i < iMaxRetries; ++i) + { + HANDLE hMutex = CreateMutex(NULL, FALSE, pszClass); + + DWORD dw = GetLastError(); + + if(NULL == hMutex) + { + HRESULT hr; + + switch(dw) + { + case ERROR_INVALID_HANDLE: + // A non-mutext object with this name already exists. + hr = E_INVALIDARG; + break; + default: + // This should never happen... + hr = E_FAIL; + } + + return hr; + } + + // If the mutex already exists, then there should be another instance running + if(dw == ERROR_ALREADY_EXISTS) + { + CloseHandle(hMutex); + + HWND hwnd = NULL; + if (bDialog) + hwnd = FindWindow(NULL, pszClass); + else + hwnd = FindWindow(pszClass, NULL); + + if(hwnd == NULL) + { + Sleep(dRetryInterval); + continue; + } + else + { + // Transmit our params to previous instance + if (lpstrCmdLine && *lpstrCmdLine) + { + COPYDATASTRUCT cd = { NULL, sizeof(TCHAR) * (wcslen(lpstrCmdLine) + 1), (PVOID)lpstrCmdLine }; + ::SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cd); + } + // Set the previous instance as the foreground window + if(0 != SetForegroundWindow(reinterpret_cast(reinterpret_cast(hwnd) | 0x1))) + return S_FALSE; + } + } + else + { + return S_OK; + } + } + return S_OK; + } + +// Operations overriden in derived class + bool AppHibernate(bool /*bHibernate*/) + { + return false; + } + + bool AppNewInstance(LPCTSTR /*lpstrCmdLine*/) + { + return false; + } + + void AppSave() + { + } + +#ifdef WIN32_PLATFORM_WFSP + void AppBackKey() + { + ::SHNavigateBack(); + } +#endif + +// Message map and handlers + BEGIN_MSG_MAP(CAppWindowBase) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) +#ifdef WIN32_PLATFORM_WFSP + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) +#else + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) +#endif // WIN32_PLATFORM_WFSP + MESSAGE_HANDLER(WM_HIBERNATE, OnHibernate) + MESSAGE_HANDLER(WM_COPYDATA, OnNewInstance) + MESSAGE_HANDLER(WM_CLOSE, OnClose) + END_MSG_MAP() + + LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + if (m_bHibernate) + m_bHibernate = pT->AppHibernate(false); +#ifndef WIN32_PLATFORM_WFSP + ::SHHandleWMActivate(pT->m_hWnd, wParam, lParam, &m_sai, 0); +#else + wParam; + lParam; +#endif // WIN32_PLATFORM_WFSP + return bHandled = FALSE; + } + +#ifdef WIN32_PLATFORM_WFSP +// SmartPhone VK_TBACK key standard management + LRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + const UINT uModif = (UINT)LOWORD(lParam); + const UINT uVirtKey = (UINT)HIWORD(lParam); + if(uVirtKey == VK_TBACK) + if (AtlIsEditFocus()) + ::SHSendBackToFocusWindow(uMsg, wParam, lParam); + else if (uModif & MOD_KEYUP) + pT->AppBackKey(); + return 1; + } + +#else // !WIN32_PLATFORM_WFSP +// PPC SIP handling + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + T* pT = static_cast(this); + bHandled = FALSE; + return ::SHHandleWMSettingChange(pT->m_hWnd, wParam, lParam, &m_sai); + } +#endif // !WIN32_PLATFORM_WFSP + + LRESULT OnHibernate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + return m_bHibernate = pT->AppHibernate(true); + } + + LRESULT OnNewInstance(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam; + return pT->AppNewInstance((LPCTSTR)pcds->lpData); + } + + LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + pT->AppSave(); + bHandled = FALSE; + return 1; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CAppWindow - PPC/SmartPhone "well-behaved" application window class + +template +class CAppWindow : public CAppWindowBase< T > +{ +public: + // Same as WTL 7.1 AppWizard generated Run + lpstrCmdLine in CreateEx + static int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL) + { + CMessageLoop theLoop; + _Module.AddMessageLoop(&theLoop); + + T wndMain; + + if(wndMain.CreateEx(NULL, NULL, 0, 0, lpstrCmdLine) == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("Main window creation failed!\n")); + return 0; + } + + wndMain.ShowWindow(nCmdShow); + + int nRet = theLoop.Run(); + + _Module.RemoveMessageLoop(); + return nRet; + } + + static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine) + { + return CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, false); + } +}; + + +#ifndef _WTL_CE_NO_DIALOGS + +/////////////////////////////////////////////////////////////////////////////// +// CAppDialog - PPC/SmartPhone "well-behaved" dialog application class + +// Macro for declaring dialog WNDCLASS and AppKey +#define DECLARE_APP_DLG_CLASS(WndClassName, uCommonResourceID, uAppKey) \ + static WTL::CFrameWndClassInfo& GetWndClassInfo() \ + { \ + static WTL::CFrameWndClassInfo wc = \ + { \ + { 0, (WNDPROC)StartDialogProc, \ + 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \ + NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ + }; \ + return wc; \ + }; \ + DECLARE_APPKEY(uAppKey) + +template +class CAppDialog : public CAppWindowBase< T > +{ +public: + static int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL) + { + CMessageLoop theLoop; + _Module.AddMessageLoop(&theLoop); + + T dlgMain; + + if(dlgMain.Create(NULL, (LPARAM)lpstrCmdLine) == NULL) + { + ATLTRACE2(atlTraceUI, 0, _T("Main dialog creation failed!\n")); + return 0; + } + + dlgMain.ShowWindow(nCmdShow); + + int nRet = theLoop.Run(); + + _Module.RemoveMessageLoop(); + return nRet; + } + + static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine) + { + return CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, true); + }; +}; + +// PPC/SmartPhone standard application dialogs + +#ifdef WIN32_PLATFORM_WFSP +#define WTL_APP_SHIDIF WTL_SP_SHIDIF +#else +#define WTL_APP_SHIDIF WTL_STD_SHIDIF +#endif + +/////////////////////////////////////////////////////////////////////////////// +// CAppStdDialogImplBase - Base implementation of standard application dialogs + +template +class ATL_NO_VTABLE CAppStdDialogImplBase : + public TImplBase, + public CAppDialog< T > +{ +public: + WTL_DLG_NOTITLE; + + void StdCloseDialog(int nVal) + { + T* pT = static_cast(this); + if (nVal != IDCANCEL) + pT->AppSave(); + if (t_bModal == false) + { + pT->DestroyWindow(); + ::PostQuitMessage(nVal); + } + else + ::EndDialog(pT->m_hWnd, nVal); + } + + BEGIN_MSG_MAP(CAppStdDialogImplBase) + MESSAGE_HANDLER(WM_CLOSE, OnSystemClose) + CHAIN_MSG_MAP(TImplBase) + CHAIN_MSG_MAP(CAppDialog< T >) + END_MSG_MAP() + + LRESULT OnSystemClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + { + T* pT = static_cast(this); + pT->StdCloseDialog(IDCANCEL); + return 0; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// CAppStdDialogImpl - Implementation of standard application dialog + +template +class ATL_NO_VTABLE CAppStdDialogImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; + +/////////////////////////////////////////////////////////////////////////////// +// CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog + +template +class ATL_NO_VTABLE CAppStdDialogResizeImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; + +#ifndef _ATL_NO_HOSTING +/////////////////////////////////////////////////////////////////////////////// +// CAppStdAxDialogImpl - Implementation of standard application AxDialog + +template +class ATL_NO_VTABLE CAppStdAxDialogImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; + +/////////////////////////////////////////////////////////////////////////////// +// CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog + +template +class ATL_NO_VTABLE CAppStdAxDialogResizeImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; +#endif // _ATL_NO_HOSTING + +#if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC) +/////////////////////////////////////////////////////////////////////////////// +// CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog + +template +class ATL_NO_VTABLE CAppStdOrientedDialogImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; + +#ifndef _ATL_NO_HOSTING +/////////////////////////////////////////////////////////////////////////////// +// CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog + +template +class ATL_NO_VTABLE CAppStdAxOrientedDialogImpl : + public CAppStdDialogImplBase, t_shidiFlags, t_bModal> +{}; +#endif // _ATL_NO_HOSTING + +#endif // defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC) + +#endif // _WTL_CE_NO_DIALOGS + +#endif // _WTL_CE_NO_APPWINDOW + + +// --- Full screen support --- + +#ifndef _WTL_CE_NO_FULLSCREEN + +/////////////////////////////////////////////////////////////////////////////// +// CFullScreenFrame - full screen frame implementation + +template +class CFullScreenFrame +{ +public: + bool m_bFullScreen; + + CFullScreenFrame() : m_bFullScreen(false) + { } + +// Operation + void SetFullScreen(bool bFull) + { + m_bFullScreen = bFull; + ShowTaskBar(!bFull, false); + ShowMenuBar(!bFull); + } + +// Manage TaskBar for modal dialogs and property sheets + template + int FSDoModal(D& dlg) + { + T* pT = static_cast(this); + pT; // avoid level 4 warning + ATLASSERT(pT->IsWindow()); + if (m_bFullScreen) // Show taskbar if hidden + ShowTaskBar(true, false); + int iRet = dlg.DoModal(); + if (m_bFullScreen) // Hide taskbar if restored + ShowTaskBar(false); + return iRet; + } + +// Implementation + void ShowMenuBar(bool bShow) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + ATL::CWindow MenuBar = pT->m_hWndCECommandBar; + ATLASSERT(MenuBar.IsWindow()); + MenuBar.ShowWindow(bShow ? SW_SHOWNORMAL : SW_HIDE); + pT->SizeToMenuBar(); + } + + void ShowTaskBar(bool bShow, bool bRepaint = true) + { + T* pT = static_cast(this); + ATLASSERT(pT->IsWindow()); + RECT rect = { 0 }; + SystemParametersInfo(SPI_GETWORKAREA, NULL, &rect, FALSE); + if (!bShow) + rect.top = 0; + +#ifdef WIN32_PLATFORM_PSPC // Pocket PC code + UINT uShow = t_bHasSip ? SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON : SHFS_SHOWTASKBAR | SHFS_HIDESIPBUTTON; + SHFullScreen(pT->m_hWnd, bShow ? uShow : SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON); +#elif _WIN32_WCE > 0x500 // Smartphone 2005 code + SHFullScreen(pT->m_hWnd, bShow ? SHFS_SHOWTASKBAR : SHFS_HIDETASKBAR); +#else // Smartphone 2003 + HWND hTaskBar = FindWindow(_T("tray"), NULL); + ATLASSERT(::IsWindow(hTaskBar)); + ::ShowWindow(hTaskBar, bShow ? SW_SHOW : SW_HIDE); +#endif // WIN32_PLATFORM_PSPC + + pT->MoveWindow(&rect, bRepaint); + } + +// Message map and handler + BEGIN_MSG_MAP(CFullScreenFrame) + MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) + MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) + END_MSG_MAP() + + LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { +#ifndef SETTINGCHANGE_RESET // not defined for PPC 2002 + #define SETTINGCHANGE_RESET SPI_SETWORKAREA +#endif + if (m_bFullScreen && (wParam & SETTINGCHANGE_RESET)) + SetFullScreen(m_bFullScreen); + return bHandled = FALSE; + } + + LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + if (m_bFullScreen) + { + ShowTaskBar(!wParam); + ShowMenuBar(!wParam); + } + return bHandled = FALSE; + } +}; + +#endif // _WTL_CE_NO_FULLSCREEN + + +// --- WinCE zoom support --- + +#ifndef _WTL_CE_NO_ZOOMSCROLL + +/////////////////////////////////////////////////////////////////////////////// +// CZoomScrollImpl - WinCE zooming implementation on top of CScrollImpl + +template +class CZoomScrollImpl: public CScrollImpl< T > +{ +public: +// Data members + _WTYPES_NS::CSize m_sizeTrue; + double m_fzoom; + +// Creation + CZoomScrollImpl() : m_sizeTrue(0), m_fzoom(1.) + { } + +// Zoom operations and access + void SetZoomScrollSize(_WTYPES_NS::CSize sizeTrue, double fzoom = 1., BOOL bRedraw = TRUE) + { + ATLASSERT(fzoom > 0.); + m_sizeTrue = sizeTrue; + m_fzoom = fzoom; + + CScrollImpl< T >::SetScrollSize(sizeTrue / fzoom, bRedraw); + } + + void SetZoomScrollSize(int cx, int cy, double fzoom=1., BOOL bRedraw = TRUE) + { + SetZoomScrollSize(_WTYPES_NS::CSize(cx, cy), fzoom, bRedraw); + } + + void SetZoom(double fzoom, BOOL bRedraw = TRUE) + { + _WTYPES_NS::CPoint ptCenter = WndtoTrue(m_sizeClient / 2); + _WTYPES_NS::CSize sizePage = GetScrollPage(); + _WTYPES_NS::CSize sizeLine = GetScrollLine(); + + SetZoomScrollSize(GetScrollSize(), fzoom, bRedraw); + + SetScrollLine(sizeLine); + SetScrollPage(sizePage); + _WTYPES_NS::CPoint ptOffset = ptCenter - (m_sizeClient / 2) * fzoom; + SetScrollOffset(ptOffset, bRedraw); + } + + double GetZoom() + { + return m_fzoom; + } + +// CScrollImpl overrides + void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) + { + CScrollImpl< T >::SetScrollOffset((int)(x / m_fzoom), (int)(y / m_fzoom), bRedraw); + } + + void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) + { + SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); + } + + void GetScrollOffset(POINT& ptOffset) + { + ptOffset.x = (LONG)(m_ptOffset.x * m_fzoom); + ptOffset.y = (LONG)(m_ptOffset.y * m_fzoom); + } + + void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE) + { + SetZoomScrollSize(cx, cy, GetZoom(), bRedraw); + } + + void SetScrollSize(SIZE sizeTrue, BOOL bRedraw = TRUE) + { + SetZoomScrollSize(sizeTrue, GetZoom(), bRedraw); + } + + void GetScrollSize(SIZE& sizeTrue) const + { + sizeTrue = m_sizeTrue; + } + + void SetScrollPage(int cxPage, int cyPage) + { + SetScrollPage(_WTYPES_NS::CSize(cxPage, cyPage)); + } + + void SetScrollPage(SIZE sizePage) + { + CScrollImpl< T >::SetScrollPage(sizePage / m_fzoom); + } + + void GetScrollPage(SIZE& sizePage) const + { + sizePage = m_sizePage * m_fzoom; + } + + void SetScrollLine(int cxLine, int cyLine) + { + SetScrollLine(_WTYPES_NS::CSize(cxLine, cyLine)); + } + + void SetScrollLine(SIZE sizeLine) + { + CScrollImpl< T >::SetScrollLine(sizeLine / m_fzoom); + } + + void GetScrollLine(SIZE& sizeLine) const + { + sizeLine = m_sizeLine * m_fzoom; + } + +// Data access complements + _WTYPES_NS::CSize GetScrollSize() + { + return m_sizeTrue; + } + + _WTYPES_NS::CSize GetScrollPage() + { + return m_sizePage * m_fzoom; + } + + _WTYPES_NS::CSize GetScrollLine() + { + return m_sizeLine * m_fzoom; + } + + _WTYPES_NS::CPoint GetScrollOffset() + { + return (_WTYPES_NS::CSize)m_ptOffset * m_fzoom; + } + +// Helper coordinate functions + _WTYPES_NS::CPoint WndtoTrue(CPoint ptW) + { + return (_WTYPES_NS::CSize)ptW * GetZoom() + GetScrollOffset(); + } + + void WndtoTrue(LPPOINT aptW, int nPts) // in place coord transformation + { + for (int i = 0 ; i < nPts ; i++) + aptW[i] = WndtoTrue(aptW[i]); + } + + void WndtoTrue(LPRECT prectW) // in place coord transformation + { + WndtoTrue((LPPOINT)prectW, 2); + } + + _WTYPES_NS::CPoint TruetoWnd(CPoint ptT) + { + return (ptT - GetScrollOffset()) / GetZoom(); + } + + void TruetoWnd(LPPOINT aptT, int nPts) // in place coord transformation + { + for (int i = 0 ; i < nPts ; i++) + aptT[i] = TruetoWnd(aptT[i]); + } + + void TruetoWnd(LPRECT prectT) // in place coord transformation + { + TruetoWnd((LPPOINT)prectT, 2); + } + +// Drawing operations : assume adequate setting of data members + BOOL Draw(HBITMAP hbm, HDC hdestDC, DWORD dwROP = SRCCOPY) + { + CDC memDC = CreateCompatibleDC(hdestDC); + CBitmapHandle bmpOld = memDC.SelectBitmap(hbm); + BOOL bRes = Draw(memDC, hdestDC, dwROP); + memDC.SelectBitmap(bmpOld); + return bRes; + } + + BOOL Draw(HDC hsourceDC, HDC hdestDC, DWORD dwROP = SRCCOPY) + { + CDCHandle destDC = hdestDC; + destDC.SetViewportOrg(0,0); + _WTYPES_NS::CPoint ptOffset = GetScrollOffset(); + _WTYPES_NS::CSize sizeZClient = m_sizeClient * GetZoom(); + return destDC.StretchBlt(0, 0, m_sizeClient.cx, m_sizeClient.cy, hsourceDC, ptOffset.x, ptOffset.y, sizeZClient.cx, sizeZClient.cy, dwROP); + } + +#ifdef _IMAGING_H + BOOL Draw(IImage* pIImage, HDC hdestDC) + { + CDCHandle destDC = hdestDC; + destDC.SetViewportOrg(0,0); + return SUCCEEDED(pIImage->Draw(destDC, _WTYPES_NS::CRect(-_WTYPES_NS::CPoint(m_ptOffset), m_sizeAll), NULL)); + } +#endif + +// Message map and handlers + BEGIN_MSG_MAP(CZoomScrollImpl< T >) + MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) + CHAIN_MSG_MAP(CScrollImpl< T >) + END_MSG_MAP() + + LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + T* pT = static_cast(this); + ATLASSERT(::IsWindow(pT->m_hWnd)); + if ((GetScrollExtendedStyle() & SCRL_ERASEBACKGROUND)) + { + _WTYPES_NS::CRect rect; + pT->GetClientRect(rect); + _WTYPES_NS::CSize sizeClient=rect.Size(); + + if (m_sizeAll.cx < sizeClient.cx || m_sizeAll.cy < sizeClient.cy) + { + CDCHandle hdc = (HDC)wParam; + HBRUSH hbr = GetSysColorBrush((int)T::GetWndClassInfo().m_wc.hbrBackground - 1); + + if (m_sizeAll.cx < sizeClient.cx) + { + _WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(m_sizeAll.cx, 0), sizeClient); + hdc.FillRect(rectBG, hbr); + } + + if (m_sizeAll.cy < sizeClient.cy) + { + _WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(0, m_sizeAll.cy), sizeClient); + hdc.FillRect(rectBG, hbr); + } + } + } + else + { + bHandled = FALSE; + } + + return 1; + } +}; + +#endif // _WTL_CE_NO_ZOOMSCROLL + +#ifndef _WTL_CE_NO_CONTROLS + +// --- PPC bottom TabView control --- + +#if defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC) + +/////////////////////////////////////////////////////////////////////////////// +// CBottomTabViewImpl + +template +class ATL_NO_VTABLE CBottomTabViewImpl : public CTabViewImpl +{ +public: + DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE) + +// Implementation overrideables + bool CreateTabControl() + { + m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | TCS_BOTTOM, 0, m_nTabID); + + ATLASSERT(m_tab.m_hWnd != NULL); + if(m_tab.m_hWnd == NULL) + return false; + + m_tab.SendMessage(CCM_SETVERSION, COMCTL32_VERSION); + m_tab.SetItemExtra(sizeof(TABVIEWPAGE)); + + T* pT = static_cast(this); + m_cyTabHeight = pT->CalcTabHeight(); + + return true; + } + + int CalcTabHeight() + { + int nCount = m_tab.GetItemCount(); + TCITEMEXTRA tcix = { 0 }; + tcix.tciheader.mask = TCIF_TEXT; + tcix.tciheader.pszText = _T("NS"); + int nIndex = m_tab.InsertItem(nCount, tcix); + + RECT rect = { 0 }; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0); + RECT rcWnd = rect; + + m_tab.AdjustRect(FALSE, &rect); + rcWnd.top = rect.bottom; + ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle()); + m_tab.DeleteItem(nIndex); + + return rcWnd.bottom - rcWnd.top; + } + + void UpdateLayout() + { + RECT rect; + GetClientRect(&rect); + + if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0)) + m_tab.SetWindowPos(NULL, 0, rect.bottom - m_cyTabHeight, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER /*| SWP_SHOWWINDOW*/); + + if(m_nActivePage != -1) + ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, 0, rect.right - rect.left, rect.bottom - m_cyTabHeight, SWP_NOZORDER); + } + +}; + +class CBottomTabView : public CBottomTabViewImpl +{ +public: + DECLARE_WND_CLASS_EX(_T("WTL_BottomTabView"), 0, COLOR_APPWORKSPACE) +}; + +#endif // defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC) + + +// --- PPC/SmartPhone controls --- + +//////////////////////////////////////////////////////////////////////////////// +// These are wrapper classes for the Pocket PC 2002/2003 and SmartPhone 2003 controls +// To implement a window based on a control, use following: +// Example: Implementing a window based on a Html control +// +// class CMyHtml : CWindowImpl +// { +// public: +// BEGIN_MSG_MAP(CMyHtml) +// // put your message handler entries here +// END_MSG_MAP() +// }; +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// CHtmlCtrl + +template +class CHtmlCtrlT : public TBase +{ +public: +// Constructors + CHtmlCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CHtmlCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call InitHTMLControl(hInstance) ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_HTML; + } + +#if (_WIN32_WCE >= 400) + void AddStyle(LPCWSTR pszStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDSTYLE, 0, (LPARAM)pszStyle); + } +#endif // (_WIN32_WCE >= 400) + + void AddText(BOOL bPlainText, LPCSTR pszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)bPlainText, (LPARAM)pszText); + } + + void AddHTML(LPCSTR pszHTML) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)FALSE, (LPARAM)pszHTML); + } + + void AddText(BOOL bPlainText, LPCWSTR pszText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)bPlainText, (LPARAM)pszText); + } + + void AddHTML(LPCWSTR pszHTML) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)FALSE, (LPARAM)pszHTML); + } + + void Anchor(LPCSTR pszAnchor) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ANCHOR, 0, (LPARAM)pszAnchor); + } + + void Anchor(LPCWSTR pszAnchor) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ANCHORW, 0, (LPARAM)pszAnchor); + } + +#if (_WIN32_WCE >= 420) + void GetBrowserDispatch(IDispatch** ppDispatch) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(ppDispatch); + ATLASSERT(*ppDispatch==NULL); + ::SendMessage(m_hWnd, DTM_BROWSERDISPATCH, 0, (LPARAM)ppDispatch); + } + void GetDocumentDispatch(IDispatch** ppDispatch) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(ppDispatch); + ATLASSERT(*ppDispatch==NULL); + ::SendMessage(m_hWnd, DTM_DOCUMENTDISPATCH , 0, (LPARAM)ppDispatch); + } +#endif // (_WIN32_WCE >= 420) + + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_CLEAR, 0, 0L); + } + + void EnableClearType(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENABLECLEARTYPE, 0, (LPARAM)bEnable); + } + + void EnableContextMenu(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENABLECONTEXTMENU, 0, (LPARAM)bEnable); + } + + void EnableScripting(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENABLESCRIPTING, 0, (LPARAM)bEnable); + } + + void EnableShrink(BOOL bEnable = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENABLESHRINK, 0, (LPARAM)bEnable); + } + + void EndOfSource() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ENDOFSOURCE, 0, 0L); + } + + void ImageFail(DWORD dwCookie) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_IMAGEFAIL, 0, (LPARAM)dwCookie); + } + + int GetLayoutHeight() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DTM_LAYOUTHEIGHT, 0, 0L); + } + + int GetLayoutWidth() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DTM_LAYOUTWIDTH, 0, 0L); + } + + void Navigate(LPCTSTR pstrURL, UINT uFlags = 0) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrURL); + ::SendMessage(m_hWnd, DTM_NAVIGATE, (WPARAM)uFlags, (LPARAM)pstrURL); + } + + void SelectAll() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_SELECTALL, 0, 0L); + } + + void SetImage(INLINEIMAGEINFO* pImageInfo) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pImageInfo); + ::SendMessage(m_hWnd, DTM_SETIMAGE, 0, (LPARAM)pImageInfo); + } + + void ZoomLevel(int iLevel) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_ZOOMLEVEL, 0, (LPARAM)iLevel); + } + +#if (_WIN32_WCE >= 400) + void Stop() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DTM_STOP, 0, 0L); + } +#endif // (_WIN32_WCE >= 400) + + void GetScriptDispatch(IDispatch** ppDispatch) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(ppDispatch); + ATLASSERT(*ppDispatch==NULL); + ::SendMessage(m_hWnd, DTM_SCRIPTDISPATCH, 0, (LPARAM)ppDispatch); + } +}; + +typedef CHtmlCtrlT CHtmlCtrl; + + +#ifdef WIN32_PLATFORM_PSPC + +/////////////////////////////////////////////////////////////////////////////// +// CRichInkCtrl + +template +class CRichInkCtrlT : public TBase +{ +public: +// Constructors + CRichInkCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CRichInkCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call InitRichInkDLL() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_RICHINK; + } + + BOOL CanPaste(UINT uFormat = 0) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, (WPARAM)uFormat, 0L); + } + + BOOL CanRedo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L); + } + + BOOL CanUndo() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L); + } + + void ClearAll(BOOL bRepaint = TRUE) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_CLEARALL, (WPARAM)bRepaint, 0L); + } + + BOOL GetModify() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L); + } + + UINT GetPageStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETPAGESTYLE, 0, 0L); + } + + UINT GetPenMode() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETPENMODE, 0, 0L); + } + + UINT GetViewStyle() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETVIEW, 0, 0L); + } + + UINT GetWrapMode() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETWRAPMODE, 0, 0L); + } + + UINT GetZoomPercent() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_GETZOOMPERCENT, 0, 0L); + } + + void InsertLinks(LPWSTR lpString, int cchLength = -1) + { + ATLASSERT(::IsWindow(m_hWnd)); + if(cchLength == -1) + cchLength = lstrlen(lpString); + ::SendMessage(m_hWnd, EM_INSERTLINKS, (WPARAM)cchLength, (LPARAM)lpString); + } + + void RedoEvent() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_REDOEVENT, 0, 0L); + } + + UINT SetInkLayer(UINT uLayer) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (UINT)::SendMessage(m_hWnd, EM_SETINKLAYER, (WPARAM)uLayer, 0L); + } + + void SetPageStyle(UINT uStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETPAGESTYLE, (WPARAM)uStyle, 0L); + } + + void SetPenMode(UINT uMode) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETPENMODE, (WPARAM)uMode, 0L); + } + + void SetViewStyle(UINT uStyle) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETVIEW, (WPARAM)uStyle, 0L); + } + + void SetViewAttributes(VIEWATTRIBUTES* pAttribs) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pAttribs); + ::SendMessage(m_hWnd, EM_SETVIEWATTRIBUTES, 0, (LPARAM)pAttribs); + } + + void SetWrapMode(UINT uMode) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETWRAPMODE, (WPARAM)uMode, 0L); + } + + void SetZoomPercent(UINT uPercent) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETZOOMPERCENT, (WPARAM)uPercent, 0L); + } + + LONG StreamIn(UINT uFormat, EDITSTREAM& es) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_STREAMIN, (WPARAM)uFormat, (LPARAM)&es); + } + + LONG StreamOut(UINT uFormat, EDITSTREAM& es) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, (WPARAM)uFormat, (LPARAM)&es); + } + + void UndoEvent() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_UNDOEVENT, 0, 0L); + } + +// Standard EM_xxx messages + DWORD GetSel() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L); + } + + void GetSel(int& nStartChar, int& nEndChar) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); + } + + void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM)bCanUndo, (LPARAM)lpszNewText); + } + + void SetModify(BOOL bModified = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, EM_SETMODIFY, (WPARAM)bModified, 0L); + } + + int GetTextLength() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L); + } + +// Clipboard operations + void Clear() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); + } + + void Copy() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_COPY, 0, 0L); + } + + void Cut() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_CUT, 0, 0L); + } + + void Paste() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); + } +}; + +typedef CRichInkCtrlT CRichInkCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CInkXCtrl + +template +class CInkXCtrlT : public TBase +{ +public: +// Constructors + CInkXCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CInkXCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call InitInkX() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_INKX; + } + + static UINT GetHotRecordingMessage() + { + return ::RegisterWindowMessage(szHotRecording); + } + + void ClearAll() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_CLEARALL, 0, 0L); + } + + int GetData(BYTE* lpBuffer, INT cbBuffer) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpBuffer); + return (int)::SendMessage(m_hWnd, IM_GETDATA, (WPARAM)cbBuffer, (LPARAM)lpBuffer); + } + + int GetDataLen() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, IM_GETDATALEN, 0, 0L); + } + + CRichInkCtrl GetRichInk() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HWND)::SendMessage(m_hWnd, IM_GETRICHINK, 0, 0L); + } + + BOOL IsRecording() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, IM_RECORDING, 0, 0L); + } + + void ReInit() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_REINIT, 0, 0L); + } + + void SetData(const BYTE* lpInkData, INT cbInkData) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(lpInkData); + ::SendMessage(m_hWnd, IM_SETDATA, (WPARAM)cbInkData, (LPARAM)lpInkData); + } + + void VoicePlay() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_VOICE_PLAY, 0, 0L); + } + + BOOL IsVoicePlaying() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, IM_VOICE_PLAYING, 0, 0L); + } + + BOOL VoiceRecord() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, IM_VOICE_RECORD, 0, 0L); + } + + void VoiceStop() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_VOICE_STOP, 0, 0L); + } + + void ShowVoiceBar(BOOL bShow = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, IM_VOICEBAR, (WPARAM)bShow, 0L); + } +}; + +typedef CInkXCtrlT CInkXCtrl; + +#endif // WIN32_PLATFORM_PSPC + + +/////////////////////////////////////////////////////////////////////////////// +// CVoiceRecorderCtrl + +template +class CVoiceRecorderCtrlT : public TBase +{ +public: +// Constructors + CVoiceRecorderCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CVoiceRecorderCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, const POINT pt, LPTSTR pstrFileName, UINT nID, DWORD dwStyle = 0) + { + ATLASSERT(pstrFileName != NULL); + CM_VOICE_RECORDER cmvr = { 0 }; + cmvr.cb = sizeof(CM_VOICE_RECORDER); + cmvr.dwStyle = dwStyle; + cmvr.xPos = pt.x; + cmvr.yPos = pt.y; + cmvr.hwndParent = hWndParent; + cmvr.id = nID; + cmvr.lpszRecordFileName = pstrFileName; + m_hWnd = VoiceRecorder_Create(&cmvr); + return m_hWnd; + } + + HWND Create(LPCM_VOICE_RECORDER pAttribs) + { + ATLASSERT(pAttribs); + m_hWnd = VoiceRecorder_Create(pAttribs); + return m_hWnd; + } + +// Attributes + void Record() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_RECORD, 0, 0L); + } + + void Play() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_PLAY, 0, 0L); + } + + void Stop() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_STOP, 0, 0L); + } + + void Cancel() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_CANCEL, 0, 0L); + } + + void Done() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, VRM_OK, 0, 0L); + } +}; + +typedef CVoiceRecorderCtrlT CVoiceRecorderCtrl; + + +#ifdef WIN32_PLATFORM_PSPC + +/////////////////////////////////////////////////////////////////////////////// +// CDocListCtrl + +template +class CDocListCtrlT : public TBase +{ +public: +// Attributes + DOCLISTCREATE m_dlc; + TCHAR m_szPath[MAX_PATH]; + +// Constructors + CDocListCtrlT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CDocListCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, WORD wId, LPCTSTR pszFolder = NULL, LPCTSTR pstrFilter = NULL, + WORD wFilterIndex = 0, DWORD dwFlags = DLF_SHOWEXTENSION) + { + ATLASSERT(pstrFilter != NULL); // It seems to need a filter badly!! + ::ZeroMemory(&m_dlc, sizeof(DOCLISTCREATE)); + ::ZeroMemory(m_szPath, sizeof(m_szPath)); + if(pszFolder != NULL) + ::lstrcpyn(m_szPath, pszFolder, MAX_PATH - 1); + m_dlc.dwStructSize = sizeof(DOCLISTCREATE); + m_dlc.hwndParent = hWndParent; + m_dlc.pszFolder = m_szPath; + m_dlc.pstrFilter = pstrFilter; + m_dlc.wFilterIndex = wFilterIndex; + m_dlc.wId = wId; + m_dlc.dwFlags = dwFlags; + m_hWnd = DocList_Create(&m_dlc); + return m_hWnd; + } + + HWND Create(DOCLISTCREATE* pDlc) + { + m_dlc = *pDlc; + m_hWnd = DocList_Create(&m_dlc); + return m_hWnd; + } + +// Attributes + void DeleteSel() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_DELETESEL, 0, 0L); + } + + void DisableUpdates() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_DISABLEUPDATES, 0, 0L); + } + + void EnableUpdates() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_ENABLEUPDATES, 0, 0L); + } + + int GetFilterIndex() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETFILTERINDEX, 0, 0L); + } + + int GetItemCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETITEMCOUNT, 0, 0L); + } + + int GetNextItem(int iIndex, DWORD dwRelation = LVNI_ALL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)iIndex, (LPARAM)dwRelation); + } + + int GetFirstItem(DWORD dwRelation = LVNI_ALL) const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)-1, (LPARAM)dwRelation); + } + + BOOL GetNextWave(int* pIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pIndex); + return (BOOL)::SendMessage(m_hWnd, DLM_GETNEXTWAVE, 0, (LPARAM)pIndex); + } + + BOOL GetPrevWave(int* pIndex) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pIndex); + return (BOOL)::SendMessage(m_hWnd, DLM_GETPREVWAVE, 0, (LPARAM)pIndex); + } + + int GetSelCount() const + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_GETSELCOUNT, 0, 0L); + } + + BOOL GetSelPathName(LPTSTR pstrPath, int cchMax) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + return (BOOL)::SendMessage(m_hWnd, DLM_GETSELPATHNAME, (WPARAM)cchMax, (LPARAM)pstrPath); + } + + void ReceiveIR(LPCTSTR pstrPath) const + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + ::SendMessage(m_hWnd, DLM_RECEIVEIR, 0, (LPARAM)pstrPath); + } + + void Refresh() + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_REFRESH, 0, 0L); + } + + BOOL RenameMoveSelectedItems() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DLM_RENAMEMOVE, 0, 0L); + } + + int SelectAll() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (int)::SendMessage(m_hWnd, DLM_SELECTALL, 0, 0L); + } + + HRESULT SelectItem(LPCTSTR pstrPath, BOOL bVisible = TRUE) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + return (HRESULT)::SendMessage(m_hWnd, DLM_SELECTITEM, (WPARAM)bVisible, (LPARAM)pstrPath); + } + + void SendEMail(LPCTSTR pstrAttachment) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_SENDEMAIL, 0, (LPARAM)pstrAttachment); + } + + void SendIR(LPCTSTR pstrPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_SENDIR, 0, (LPARAM)pstrPath); + } + + HRESULT SetFilterIndex(int iIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, DLM_SETFILTERINDEX, (WPARAM)iIndex, 0L); + } + + void SetFolder(LPCTSTR pstrPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + ::SendMessage(m_hWnd, DLM_SETFOLDER, 0, (LPARAM)pstrPath); + } + + BOOL SetItemState(int iIndex, const LVITEM* pItem) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pItem); + return (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)pItem); + } + + BOOL SetItemState(int iIndex, UINT uState, UINT uMask) + { + ATLASSERT(::IsWindow(m_hWnd)); + LV_ITEM lvi = { 0 }; + lvi.stateMask = uMask; + lvi.state = uState; + return (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)&lvi); + } + + void SetOneItem(int iIndex, LPCVOID pPA) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_SETONEITEM, (WPARAM)iIndex, (LPARAM)pPA); + } + + void SetSelect(int iIndex) + { + ATLASSERT(::IsWindow(m_hWnd)); + ::SendMessage(m_hWnd, DLM_SETSELECT, (WPARAM)iIndex, 0L); + } + + void SetSelPathName(LPCTSTR pstrPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrPath); + ::SendMessage(m_hWnd, DLM_SETSELPATHNAME, 0, (LPARAM)pstrPath); + } + + BOOL SetSortOrder() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DLM_SETSORTORDER, 0, 0L); + } + + HRESULT Update() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (HRESULT)::SendMessage(m_hWnd, DLM_UPDATE, 0, 0L); + } + + BOOL ValidateFolder() + { + ATLASSERT(::IsWindow(m_hWnd)); + return (BOOL)::SendMessage(m_hWnd, DLM_VALIDATEFOLDER, 0, 0L); + } + +// Functions + BOOL GetFirstSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + return DocList_GetFirstSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath); + } + + BOOL GetNextSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath) + { + ATLASSERT(::IsWindow(m_hWnd)); + return DocList_GetNextSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath); + } +}; + +typedef CDocListCtrlT CDocListCtrl; + +#endif // WIN32_PLATFORM_PSPC + + +/////////////////////////////////////////////////////////////////////////////// +// CCapEdit + +template +class CCapEditT : public TBase +{ +public: +// Constructors + CCapEditT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CCapEditT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = /*TBase*/CWindow::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_CAPEDIT; + } +}; + +typedef CCapEditT CCapEdit; + +/////////////////////////////////////////////////////////////////////////////// +// CTTStatic + +#ifndef WIN32_PLATFORM_WFSP // Tooltips not supported on SmartPhone + +template +class CTTStaticT : public TBase +{ +public: +// Constructors + CTTStaticT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTTStaticT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_TSTATIC; + } + +// Operations + BOOL SetToolTipText(LPCTSTR pstrTipText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrTipText); + ATLASSERT(lstrlen(pstrTipText)<= 253); + CTempBuffer buff; + LPTSTR pstr = buff.Allocate(lstrlen(pstrTipText) + 3); + if(pstr == NULL) + return FALSE; + ::lstrcpy(pstr, _T("~~")); + ::lstrcat(pstr, pstrTipText); + return SetWindowText(pstr); + } +}; + +typedef CTTStaticT CTTStatic; + + +/////////////////////////////////////////////////////////////////////////////// +// CTTButton + +template +class CTTButtonT : public TBase +{ +public: +// Constructors + CTTButtonT(HWND hWnd = NULL) : TBase(hWnd) + { } + + CTTButtonT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + HWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); + ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ?? + return hWnd; + } + +// Attributes + static LPCTSTR GetWndClassName() + { + return WC_TBUTTON; + } + +// Operations + BOOL SetToolTipText(LPCTSTR pstrTipText) + { + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(pstrTipText); + ATLASSERT(lstrlen(pstrTipText)<= 253); + CTempBuffer buff; + LPTSTR pstr = buff.Allocate(lstrlen(pstrTipText) + 3); + if(pstr == NULL) + return FALSE; + ::lstrcpy(pstr, _T("~~")); + ::lstrcat(pstr, pstrTipText); + return SetWindowText(pstr); + } +}; + +typedef CTTButtonT CTTButton; + +#endif // !WIN32_PLATFORM_WFSP + + +// --- SmartPhone specific controls --- + +#ifdef WIN32_PLATFORM_WFSP + +/////////////////////////////////////////////////////////////////////////////// +// CSpinCtrlT - CSpinCtrl : SmartPhone adapted UpDown control + +template +class CSpinCtrlT : public CUpDownCtrlT< TBase > +{ +public: +// Constructors + CSpinCtrlT(HWND hWnd = NULL) : CUpDownCtrlT< TBase >(hWnd) + { } + + CSpinCtrlT< TBase >& operator =(HWND hWnd) + { + m_hWnd = hWnd; + return *this; + } + + HWND Create(HWND hWndParent, HWND hBuddy, DWORD dwStyle, int nID, LPCTSTR szExpandedName = NULL) + { + ATLASSERT(::IsWindow(hWndParent)); + CUpDownCtrlT< TBase >::Create(hWndParent, NULL, szExpandedName, dwStyle, 0, nID, NULL); + ATLASSERT(m_hWnd != NULL); // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)? + if (hBuddy != NULL) + { + ATLASSERT(::IsWindow(hBuddy)); + SetBuddy(hBuddy); + } + return m_hWnd; + } +}; + +typedef CSpinCtrlT CSpinCtrl; + + +/////////////////////////////////////////////////////////////////////////////// +// CSpinned - SmartPhone association of control and Spin + +template +class CSpinned : public TBase +{ +public: + CSpinCtrl m_SpinCtrl; + DWORD m_dwSpinnedStyle; + +// Constructors + CSpinned(HWND hWnd = NULL) : TBase(hWnd) + { + m_dwSpinnedStyle = WS_VISIBLE | UDS_ALIGNRIGHT | UDS_EXPANDABLE; + + if (t_bExpandOnly == true) + m_dwSpinnedStyle |= UDS_NOSCROLL; + else + m_dwSpinnedStyle |= UDS_HORZ | UDS_ARROWKEYS | UDS_SETBUDDYINT | UDS_WRAP; + + if (hWnd != NULL) + AttachOrCreateSpinCtrl(); + } + + CSpinned& operator =(HWND hWnd) + { + Attach(hWnd); + return *this; + } + + void Attach(HWND hWnd) + { + ATLASSERT(!IsWindow()); + TBase* pT = static_cast(this); + pT->m_hWnd = hWnd; + if (hWnd != NULL) + AttachOrCreateSpinCtrl(); + } + + HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szExpandedName = NULL, + DWORD dwStyle = 0, DWORD dwExStyle = 0, + ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) + { + + TBase* pT = static_cast(this); + TBase::Create(hWndParent, rect, NULL, dwStyle, dwExStyle, MenuOrID, lpCreateParam); + ATLASSERT(pT->m_hWnd != NULL); + + m_SpinCtrl.Create(hWndParent, pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + (int)MenuOrID.m_hMenu, szExpandedName); + + ATLASSERT(m_SpinCtrl.m_hWnd != NULL); // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)? + + return pT->m_hWnd; + } + +// Attributes + CSpinCtrl& GetSpinCtrl() + { + return m_SpinCtrl; + } + +// Implementation + // Attach our existing SpinCtrl or create one + bool AttachOrCreateSpinCtrl() + { + TBase* pT = static_cast(this); + + HWND hSpin = ::GetDlgItem(pT->GetParent(), ATL_IDW_SPIN_ID + pT->GetDlgCtrlID()); + + if (hSpin != NULL) + { + m_SpinCtrl.Attach(hSpin); +#ifdef DEBUG + TCHAR sClassName[16]; + ::GetClassName(hSpin, sClassName, 16); + ATLASSERT(!_tcscmp(sClassName, UPDOWN_CLASS)); + ATLASSERT(m_SpinCtrl.GetBuddy().m_hWnd == pT->m_hWnd); +#endif // DEBUG + } + else + { + m_SpinCtrl.Create(pT->GetParent(), pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + pT->GetDlgCtrlID()); + } + + return m_SpinCtrl.m_hWnd != NULL; + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// CSpinListBox - SmartPhone spinned ListBox control +// CExpandListBox - SmartPhone expandable ListBox control +// CExpandEdit - SmartPhone expandable Edit control +// CExpandCapEdit - SmartPhone expandable CapEdit control + +typedef CSpinned CSpinListBox; +typedef CSpinned CExpandListBox; +typedef CSpinned CExpandEdit; +typedef CSpinned CExpandCapEdit; + +#endif // WIN32_PLATFORM_WFSP + +#endif // _WTL_CE_NO_CONTROLS + +}; // namespace WTL + +#endif // __ATLWINCE_H__ diff --git a/wtl/wtl/include/atlwinx.h b/wtl/wtl/include/atlwinx.h new file mode 100644 index 00000000..9767fa10 --- /dev/null +++ b/wtl/wtl/include/atlwinx.h @@ -0,0 +1,529 @@ +// Windows Template Library - WTL version 8.0 +// Copyright (C) Microsoft Corporation. All rights reserved. +// +// This file is a part of the Windows Template Library. +// The use and distribution terms for this software are covered by the +// Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) +// which can be found in the file CPL.TXT at the root of this distribution. +// By using this software in any fashion, you are agreeing to be bound by +// the terms of this license. You must not remove this notice, or +// any other, from this software. + +#ifndef __ATLWINX_H__ +#define __ATLWINX_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error atlwinx.h requires atlapp.h to be included first +#endif + +#if (_ATL_VER >= 0x0700) + #include +#endif // (_ATL_VER >= 0x0700) + + +/////////////////////////////////////////////////////////////////////////////// +// Classes in this file: +// +// _U_RECT +// _U_MENUorID +// _U_STRINGorID + + +/////////////////////////////////////////////////////////////////////////////// +// Command Chaining Macros + +#define CHAIN_COMMANDS(theChainClass) \ + if(uMsg == WM_COMMAND) \ + CHAIN_MSG_MAP(theChainClass) + +#define CHAIN_COMMANDS_ALT(theChainClass, msgMapID) \ + if(uMsg == WM_COMMAND) \ + CHAIN_MSG_MAP_ALT(theChainClass, msgMapID) + +#define CHAIN_COMMANDS_MEMBER(theChainMember) \ + if(uMsg == WM_COMMAND) \ + CHAIN_MSG_MAP_MEMBER(theChainMember) + +#define CHAIN_COMMANDS_ALT_MEMBER(theChainMember, msgMapID) \ + if(uMsg == WM_COMMAND) \ + CHAIN_MSG_MAP_ALT_MEMBER(theChainMember, msgMapID) + + +/////////////////////////////////////////////////////////////////////////////// +// Macros for parent message map to selectively reflect control messages + +// NOTE: ReflectNotifications is a member of ATL's CWindowImplRoot +// (and overridden in 2 cases - CContainedWindowT and CAxHostWindow) +// Since we can't modify ATL, we'll provide the needed additions +// in a separate function (that is not a member of CWindowImplRoot) + +namespace WTL +{ + +inline LRESULT WtlReflectNotificationsFiltered(HWND hWndParent, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled, + UINT uMsgFilter = WM_NULL, UINT_PTR idFromFilter = 0, HWND hWndChildFilter = NULL) +{ + if((uMsgFilter != WM_NULL) && (uMsgFilter != uMsg)) + { + // The notification message doesn't match the filter. + bHandled = FALSE; + return 1; + } + + HWND hWndChild = NULL; + UINT_PTR idFrom = 0; + + switch(uMsg) + { + case WM_COMMAND: + if(lParam != NULL) // not from a menu + { + hWndChild = (HWND)lParam; + idFrom = (UINT_PTR)LOWORD(wParam); + } + break; + case WM_NOTIFY: + hWndChild = ((LPNMHDR)lParam)->hwndFrom; + idFrom = ((LPNMHDR)lParam)->idFrom; + break; +#ifndef _WIN32_WCE + case WM_PARENTNOTIFY: + switch(LOWORD(wParam)) + { + case WM_CREATE: + case WM_DESTROY: + hWndChild = (HWND)lParam; + idFrom = (UINT_PTR)HIWORD(wParam); + break; + default: + hWndChild = ::GetDlgItem(hWndParent, HIWORD(wParam)); + idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); + break; + } + break; +#endif // !_WIN32_WCE + case WM_DRAWITEM: + if(wParam) // not from a menu + { + hWndChild = ((LPDRAWITEMSTRUCT)lParam)->hwndItem; + idFrom = (UINT_PTR)wParam; + } + break; + case WM_MEASUREITEM: + if(wParam) // not from a menu + { + hWndChild = ::GetDlgItem(hWndParent, ((LPMEASUREITEMSTRUCT)lParam)->CtlID); + idFrom = (UINT_PTR)wParam; + } + break; + case WM_COMPAREITEM: + if(wParam) // not from a menu + { + hWndChild = ((LPCOMPAREITEMSTRUCT)lParam)->hwndItem; + idFrom = (UINT_PTR)wParam; + } + break; + case WM_DELETEITEM: + if(wParam) // not from a menu + { + hWndChild = ((LPDELETEITEMSTRUCT)lParam)->hwndItem; + idFrom = (UINT_PTR)wParam; + } + break; + case WM_VKEYTOITEM: + case WM_CHARTOITEM: + case WM_HSCROLL: + case WM_VSCROLL: + hWndChild = (HWND)lParam; + idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); + break; + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + hWndChild = (HWND)lParam; + idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); + break; + default: + break; + } + + if((hWndChild == NULL) || + ((hWndChildFilter != NULL) && (hWndChildFilter != hWndChild))) + { + // Either hWndChild isn't valid, or + // hWndChild doesn't match the filter. + bHandled = FALSE; + return 1; + } + + if((idFromFilter != 0) && (idFromFilter != idFrom)) + { + // The dialog control id doesn't match the filter. + bHandled = FALSE; + return 1; + } + + ATLASSERT(::IsWindow(hWndChild)); + LRESULT lResult = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam); + if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) + { + // Try to prevent problems with WM_CTLCOLOR* messages when + // the message wasn't really handled + bHandled = FALSE; + } + + return lResult; +} + +}; // namespace WTL + +// Try to prevent problems with WM_CTLCOLOR* messages when +// the message wasn't really handled +#define REFLECT_NOTIFICATIONS_EX() \ +{ \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) \ + bHandled = FALSE; \ + if(bHandled) \ + return TRUE; \ +} + +#define REFLECT_NOTIFICATIONS_MSG_FILTERED(uMsgFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, NULL); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFICATIONS_ID_FILTERED(idFromFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, idFromFilter, NULL); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFICATIONS_HWND_FILTERED(hWndChildFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, 0, hWndChildFilter); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFICATIONS_MSG_ID_FILTERED(uMsgFilter, idFromFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, idFromFilter, NULL); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFICATIONS_MSG_HWND_FILTERED(uMsgFilter, hWndChildFilter) \ + { \ + bHandled = TRUE; \ + lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, hWndChildFilter); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND(id, code) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND_ID(id) \ + if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND_CODE(code) \ + if(uMsg == WM_COMMAND && code == HIWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND_RANGE(idFirst, idLast) \ + if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_COMMAND_RANGE_CODE(idFirst, idLast, code) \ + if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY(id, cd) \ + if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY_ID(id) \ + if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY_CODE(cd) \ + if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY_RANGE(idFirst, idLast) \ + if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECT_NOTIFY_RANGE_CODE(idFirst, idLast, cd) \ + if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + + +/////////////////////////////////////////////////////////////////////////////// +// Reflected message handler macros for message maps (for ATL 3.0) + +#if (_ATL_VER < 0x0700) + +#define REFLECTED_COMMAND_HANDLER(id, code, func) \ + if(uMsg == OCM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_COMMAND_ID_HANDLER(id, func) \ + if(uMsg == OCM_COMMAND && id == LOWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_COMMAND_CODE_HANDLER(code, func) \ + if(uMsg == OCM_COMMAND && code == HIWORD(wParam)) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_COMMAND_RANGE_HANDLER(idFirst, idLast, func) \ + if(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_COMMAND_RANGE_CODE_HANDLER(idFirst, idLast, code, func) \ + if(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_HANDLER(id, cd, func) \ + if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_ID_HANDLER(id, func) \ + if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_CODE_HANDLER(cd, func) \ + if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_RANGE_HANDLER(idFirst, idLast, func) \ + if(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#define REFLECTED_NOTIFY_RANGE_CODE_HANDLER(idFirst, idLast, cd, func) \ + if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ + { \ + bHandled = TRUE; \ + lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +#endif // (_ATL_VER < 0x0700) + + +/////////////////////////////////////////////////////////////////////////////// +// Dual argument helper classes (for ATL 3.0) + +#if (_ATL_VER < 0x0700) + +namespace ATL +{ + +class _U_RECT +{ +public: + _U_RECT(LPRECT lpRect) : m_lpRect(lpRect) + { } + _U_RECT(RECT& rc) : m_lpRect(&rc) + { } + LPRECT m_lpRect; +}; + +class _U_MENUorID +{ +public: + _U_MENUorID(HMENU hMenu) : m_hMenu(hMenu) + { } + _U_MENUorID(UINT nID) : m_hMenu((HMENU)LongToHandle(nID)) + { } + HMENU m_hMenu; +}; + +class _U_STRINGorID +{ +public: + _U_STRINGorID(LPCTSTR lpString) : m_lpstr(lpString) + { } + _U_STRINGorID(UINT nID) : m_lpstr(MAKEINTRESOURCE(nID)) + { } + LPCTSTR m_lpstr; +}; + +}; // namespace ATL + +#endif // (_ATL_VER < 0x0700) + + +namespace WTL +{ + +/////////////////////////////////////////////////////////////////////////////// +// Forward notifications support for message maps (for ATL 3.0) + +#if (_ATL_VER < 0x0700) + +// forward notifications support +#define FORWARD_NOTIFICATIONS() \ + { \ + bHandled = TRUE; \ + lResult = WTL::Atl3ForwardNotifications(m_hWnd, uMsg, wParam, lParam, bHandled); \ + if(bHandled) \ + return TRUE; \ + } + +static LRESULT Atl3ForwardNotifications(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + LRESULT lResult = 0; + switch(uMsg) + { + case WM_COMMAND: + case WM_NOTIFY: +#ifndef _WIN32_WCE + case WM_PARENTNOTIFY: +#endif // !_WIN32_WCE + case WM_DRAWITEM: + case WM_MEASUREITEM: + case WM_COMPAREITEM: + case WM_DELETEITEM: + case WM_VKEYTOITEM: + case WM_CHARTOITEM: + case WM_HSCROLL: + case WM_VSCROLL: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + lResult = ::SendMessage(::GetParent(hWnd), uMsg, wParam, lParam); + break; + default: + bHandled = FALSE; + break; + } + return lResult; +} + +#endif // (_ATL_VER < 0x0700) + +}; // namespace WTL + +#endif // __ATLWINX_H__ From 28c814e707e5cbf5ef452c5da600a46ea1b72423 Mon Sep 17 00:00:00 2001 From: cbucher Date: Fri, 20 Aug 2010 21:04:55 +0200 Subject: [PATCH 003/207] "Flat scrollbars" checkbox was removed by error when merging --- Console/Console.rc | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index b7ec9557..b46fb63e 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -373,7 +373,8 @@ BEGIN CONTROL "Show t&abs",IDC_CHECK_SHOW_TABS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,48,49,10 CONTROL "Hide &single tab",IDC_CHECK_HIDE_SINGLE_TAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,60,59,10 CONTROL "Show scro&llbars",IDC_CHECK_SHOW_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,73,72,10 - GROUPBOX "Controls",IDC_STATIC,0,0,88,92 + CONTROL "&Flat scrollbars",IDC_CHECK_FLAT_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,85,59,10 + GROUPBOX "Controls",IDC_STATIC,0,0,88,98 CONTROL "&Caption *",IDC_CHECK_STYLE_CAPTION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,12,47,10 CONTROL "Resi&zable *",IDC_CHECK_STYLE_RESIZABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,24,52,10 CONTROL "Bo&rder *",IDC_CHECK_STYLE_BORDER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,36,43,10 @@ -384,20 +385,20 @@ BEGIN CONTROL "",IDC_SPIN_INSIDE_BORDER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,191,50,11,14 LTEXT "Selection col&or:",IDC_STATIC,102,74,50,8 CONTROL "",IDC_SELECTION_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,153,71,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Styles",IDC_STATIC,92,0,134,92 - CONTROL "&None",IDC_TRANSPARENCY_TYPE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,10,105,33,10 - CONTROL "&Alpha",IDC_TRANSPARENCY_TYPE2,"Button",BS_AUTORADIOBUTTON,10,120,34,10 - CONTROL "Color &key",IDC_TRANSPARENCY_TYPE3,"Button",BS_AUTORADIOBUTTON,10,212,46,10 - CONTROL "Glass",IDC_TRANSPARENCY_TYPE4,"Button",BS_AUTORADIOBUTTON,50,120,33,10 - LTEXT "A&ctive window",IDC_STATIC_ACTIVE_WINDOW,19,134,47,8 - CONTROL "",IDC_ACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,145,185,22 - LTEXT "255",IDC_STATIC_ACTIVE_ALPHA,204,147,14,8,0,WS_EX_RIGHT - LTEXT "&Inactive window",IDC_STATIC_INACTIVE_WINDOW,19,169,53,8 - CONTROL "",IDC_INACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,182,185,22 - LTEXT "255",IDC_STATIC_INACTIVE_ALPHA,204,184,14,8,0,WS_EX_RIGHT - LTEXT "Key col&or:",IDC_STATIC_KEY_COLOR,19,227,33,8 - CONTROL "",IDC_KEY_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,54,224,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Window transparency",IDC_STATIC,0,95,226,160 + GROUPBOX "Styles",IDC_STATIC,92,0,134,98 + CONTROL "&None",IDC_TRANSPARENCY_TYPE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,8,114,33,10 + CONTROL "&Alpha",IDC_TRANSPARENCY_TYPE2,"Button",BS_AUTORADIOBUTTON,8,129,34,10 + CONTROL "Color &key",IDC_TRANSPARENCY_TYPE3,"Button",BS_AUTORADIOBUTTON,8,218,46,10 + CONTROL "Glass",IDC_TRANSPARENCY_TYPE4,"Button",BS_AUTORADIOBUTTON,50,129,34,10 + LTEXT "A&ctive window",IDC_STATIC_ACTIVE_WINDOW,19,142,47,8 + CONTROL "",IDC_ACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,153,185,22 + LTEXT "255",IDC_STATIC_ACTIVE_ALPHA,204,155,14,8,0,WS_EX_RIGHT + LTEXT "&Inactive window",IDC_STATIC_INACTIVE_WINDOW,19,177,53,8 + CONTROL "",IDC_INACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,190,185,22 + LTEXT "255",IDC_STATIC_INACTIVE_ALPHA,204,192,14,8,0,WS_EX_RIGHT + LTEXT "Key col&or:",IDC_STATIC_KEY_COLOR,19,235,33,8 + CONTROL "",IDC_KEY_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,54,232,16,14,WS_EX_DLGMODALFRAME + GROUPBOX "Window transparency",IDC_STATIC,0,98,226,162 END IDD_SETTINGS_TEMP DIALOGEX 0, 0, 611, 555 From c656534eccfcfc4c88ce2c0b104e2c71e7a15a55 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 22 Aug 2010 23:32:28 +0200 Subject: [PATCH 004/207] option for the tabs position : "top" or "bottom" --- Console/AeroTabCtrl.h | 71 +- Console/Console.rc | 35 +- Console/Console.vcproj | 1986 ++++++++++++++++----------------- Console/DlgSettingsStyles.cpp | 2 + Console/DlgSettingsStyles.h | 2 + Console/MainFrame.cpp | 30 +- Console/SettingsHandler.cpp | 4 + Console/SettingsHandler.h | 1 + Console/resource.h | 497 +++++---- 9 files changed, 1360 insertions(+), 1268 deletions(-) diff --git a/Console/AeroTabCtrl.h b/Console/AeroTabCtrl.h index 2fd644f0..7db5d291 100644 --- a/Console/AeroTabCtrl.h +++ b/Console/AeroTabCtrl.h @@ -110,6 +110,16 @@ class CAeroTabCtrlImpl : } void DrawTab(RECT& rcTab, Gdiplus::Graphics& g, Gdiplus::Color& color) + { + DWORD dwStyle = this->GetStyle(); + + if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) + this->DrawTabBottom(rcTab, g, color); + else + this->DrawTabTop(rcTab, g, color); + } + + void DrawTabTop(RECT& rcTab, Gdiplus::Graphics& g, Gdiplus::Color& color) { Gdiplus::SolidBrush brush(color); @@ -159,12 +169,65 @@ class CAeroTabCtrlImpl : g.DrawLine(&pen2, X + width, Y + radius, X + width, Y + height); } + void DrawTabBottom(RECT& rcTab, Gdiplus::Graphics& g, Gdiplus::Color& color) + { + Gdiplus::SolidBrush brush(color); + + Gdiplus::GraphicsPath gp; + + INT radius = m_iRadius; + INT X = rcTab.left + m_iLeftSpacing; + INT Y = rcTab.bottom - m_iTopMargin; + INT width = rcTab.right - rcTab.left - m_iLeftSpacing - 2; + INT height = rcTab.bottom - rcTab.top - m_iTopMargin; + + gp.AddLine(X + radius, Y, X + width - radius, Y); + gp.AddLine(X + width - radius, Y, X + width, Y - radius); + gp.AddLine(X + width, Y - radius, X + width, Y - height); + gp.AddLine(X + width, Y - height, X, Y - height); + gp.AddLine(X, Y - height, X, Y - radius); + gp.AddLine(X, Y - radius, X + radius, Y); + + g.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); + Gdiplus::Pen pen(color,1.0); + g.DrawPath(&pen, &gp); + + g.SetSmoothingMode(Gdiplus::SmoothingModeNone); + g.FillPath(&brush, &gp); + + radius += 2; + X -= 1; + Y += 1; + width += 2; + height += 2; + + g.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); + Gdiplus::Pen pen2(Gdiplus::Color(64, 0, 0,0),1.0); + + g.DrawLine(&pen2, X, Y - radius, X + radius, Y); + g.DrawLine(&pen2, X, Y - height, X, Y - radius); + g.DrawLine(&pen2, X + radius, Y, X + width - radius, Y); + g.DrawLine(&pen2, X + width - radius, Y, X + width, Y - radius); + g.DrawLine(&pen2, X + width, Y - radius, X + width, Y - height); + } + void DrawItem_InitBounds(DWORD /*dwStyle*/, RECT /*rcItem*/, RECT& rcTab, RECT& rcText, int& nIconVerticalCenter) { - rcText.top += m_iTopMargin; - rcText.left += (m_iLeftSpacing + m_iMargin); - rcText.right -= m_iMargin; - nIconVerticalCenter = (rcTab.bottom + rcTab.top - m_iTopMargin) / 2 + m_iTopMargin; + DWORD dwStyle = this->GetStyle(); + if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) + { + rcText.bottom -= m_iTopMargin; + rcText.left += (m_iLeftSpacing + m_iMargin); + rcText.right -= m_iMargin; + nIconVerticalCenter = (rcTab.bottom + rcTab.top - m_iTopMargin) / 2; + } + else + { + rcText.top += m_iTopMargin; + rcText.left += (m_iLeftSpacing + m_iMargin); + rcText.right -= m_iMargin; + nIconVerticalCenter = (rcTab.bottom + rcTab.top - m_iTopMargin) / 2 + m_iTopMargin; + } } void DrawItem_TabInactive(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw, RECT& rcTab) diff --git a/Console/Console.rc b/Console/Console.rc index b46fb63e..c96b95d0 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -371,10 +371,11 @@ BEGIN CONTROL "Show &toolbar",IDC_CHECK_SHOW_TOOLBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,24,58,10 CONTROL "Sho&w status bar",IDC_CHECK_SHOW_STATUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,36,68,10 CONTROL "Show t&abs",IDC_CHECK_SHOW_TABS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,48,49,10 - CONTROL "Hide &single tab",IDC_CHECK_HIDE_SINGLE_TAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,60,59,10 - CONTROL "Show scro&llbars",IDC_CHECK_SHOW_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,73,72,10 - CONTROL "&Flat scrollbars",IDC_CHECK_FLAT_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,85,59,10 - GROUPBOX "Controls",IDC_STATIC,0,0,88,98 + CONTROL "Hide &single tab",IDC_CHECK_HIDE_SINGLE_TAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,60,59,10 + CONTROL "Tabs &bottom *",IDC_CHECK_TABS_BOTTOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,73,59,10 + CONTROL "Show scro&llbars",IDC_CHECK_SHOW_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,85,72,10 + CONTROL "&Flat scrollbars",IDC_CHECK_FLAT_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,97,59,10 + GROUPBOX "Controls",IDC_STATIC,0,0,88,114 CONTROL "&Caption *",IDC_CHECK_STYLE_CAPTION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,12,47,10 CONTROL "Resi&zable *",IDC_CHECK_STYLE_RESIZABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,24,52,10 CONTROL "Bo&rder *",IDC_CHECK_STYLE_BORDER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,36,43,10 @@ -385,7 +386,7 @@ BEGIN CONTROL "",IDC_SPIN_INSIDE_BORDER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,191,50,11,14 LTEXT "Selection col&or:",IDC_STATIC,102,74,50,8 CONTROL "",IDC_SELECTION_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,153,71,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Styles",IDC_STATIC,92,0,134,98 + GROUPBOX "Styles",IDC_STATIC,92,0,134,114 CONTROL "&None",IDC_TRANSPARENCY_TYPE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,8,114,33,10 CONTROL "&Alpha",IDC_TRANSPARENCY_TYPE2,"Button",BS_AUTORADIOBUTTON,8,129,34,10 CONTROL "Color &key",IDC_TRANSPARENCY_TYPE3,"Button",BS_AUTORADIOBUTTON,8,218,46,10 @@ -398,7 +399,7 @@ BEGIN LTEXT "255",IDC_STATIC_INACTIVE_ALPHA,204,192,14,8,0,WS_EX_RIGHT LTEXT "Key col&or:",IDC_STATIC_KEY_COLOR,19,235,33,8 CONTROL "",IDC_KEY_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,54,232,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Window transparency",IDC_STATIC,0,98,226,162 + GROUPBOX "Window transparency",IDC_STATIC,0,114,226,162 END IDD_SETTINGS_TEMP DIALOGEX 0, 0, 611, 555 @@ -602,7 +603,8 @@ BEGIN HORZGUIDE, 65 HORZGUIDE, 78 HORZGUIDE, 90 - HORZGUIDE, 98 + HORZGUIDE, 102 + HORZGUIDE, 114 END IDD_SETTINGS_TEMP, DIALOG @@ -850,11 +852,20 @@ END STRINGTABLE BEGIN + ID_FILE_NEW_TAB "Opens a new tab\nNew tab" ID_VIEW_CONSOLE "Show or hide the console" +END + +STRINGTABLE +BEGIN ID_VIEW_MENU "Show or hide the menu" + ID_VIEW_TABS "Show or hide the status tabs" +END + +STRINGTABLE +BEGIN ID_VIEW_TOOLBAR "Show or hide the toolbar" ID_VIEW_STATUS_BAR "Show or hide the status bar" - ID_VIEW_TABS "Show or hide the status tabs" END STRINGTABLE @@ -885,11 +896,6 @@ BEGIN ATL_IDS_MRU_FILE "Open this document" END -STRINGTABLE -BEGIN - ID_FILE_NEW_TAB "Opens a new tab\nNew tab" -END - STRINGTABLE BEGIN ID_NEXT_TAB "Switch to next tab\nNext tab" @@ -911,8 +917,7 @@ END // // Generated from the TEXTINCLUDE 3 resource. // - - + ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/Console/Console.vcproj b/Console/Console.vcproj index 72d00494..9c1fff4a 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -1,999 +1,987 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Console/DlgSettingsStyles.cpp b/Console/DlgSettingsStyles.cpp index 8177e58e..72b3951a 100644 --- a/Console/DlgSettingsStyles.cpp +++ b/Console/DlgSettingsStyles.cpp @@ -40,6 +40,7 @@ LRESULT DlgSettingsStyles::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM m_nShowStatusbar= m_controlsSettings.bShowStatusbar ? 1 : 0; m_nShowTabs = m_controlsSettings.bShowTabs ? 1 : 0; m_nHideSingleTab= m_controlsSettings.bHideSingleTab ? 1 : 0; + m_nTabsBottom = m_controlsSettings.bTabsBottom ? 1 : 0; m_nShowScrollbars= m_controlsSettings.bShowScrollbars ? 1 : 0; m_nFlatScrollbars= m_controlsSettings.bFlatScrollbars ? 1 : 0; @@ -140,6 +141,7 @@ LRESULT DlgSettingsStyles::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWn m_controlsSettings.bShowStatusbar = (m_nShowStatusbar > 0); m_controlsSettings.bShowTabs = (m_nShowTabs > 0); m_controlsSettings.bHideSingleTab = (m_nHideSingleTab > 0); + m_controlsSettings.bTabsBottom = (m_nTabsBottom > 0); m_controlsSettings.bShowScrollbars = (m_nShowScrollbars > 0); m_controlsSettings.bFlatScrollbars = (m_nFlatScrollbars > 0); diff --git a/Console/DlgSettingsStyles.h b/Console/DlgSettingsStyles.h index a719041f..6fc1af28 100644 --- a/Console/DlgSettingsStyles.h +++ b/Console/DlgSettingsStyles.h @@ -26,6 +26,7 @@ class DlgSettingsStyles DDX_CHECK(IDC_CHECK_SHOW_STATUS, m_nShowStatusbar) DDX_CHECK(IDC_CHECK_SHOW_TABS, m_nShowTabs) DDX_CHECK(IDC_CHECK_HIDE_SINGLE_TAB, m_nHideSingleTab) + DDX_CHECK(IDC_CHECK_TABS_BOTTOM, m_nTabsBottom) DDX_CHECK(IDC_CHECK_SHOW_SCROLLBARS, m_nShowScrollbars) DDX_CHECK(IDC_CHECK_FLAT_SCROLLBARS, m_nFlatScrollbars) DDX_CHECK(IDC_CHECK_STYLE_CAPTION, m_nShowCaption) @@ -84,6 +85,7 @@ class DlgSettingsStyles int m_nShowStatusbar; int m_nShowTabs; int m_nHideSingleTab; + int m_nTabsBottom; int m_nShowScrollbars; int m_nFlatScrollbars; diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index ac5e9059..014a9db9 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -150,7 +150,10 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, // initialize tabs UpdateTabsMenu(m_CmdBar.GetMenu(), m_tabsMenu); SetReflectNotifications(true); - CreateTabWindow(m_hWnd, rcDefault, CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_HOTTRACK); + DWORD dwTabWindowOtherStyles = CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_HOTTRACK; + if( g_settingsHandler->GetAppearanceSettings().controlsSettings.bTabsBottom ) + dwTabWindowOtherStyles |= CTCS_BOTTOM; + CreateTabWindow(m_hWnd, rcDefault, dwTabWindowOtherStyles); // create initial console window(s) if (m_startupTabs.size() == 0) @@ -2195,7 +2198,30 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal void MainFrame::SetMargins(void) { CReBarCtrl rebar(m_hWndToolBar); - m_Margins.cyTopHeight = rebar.GetBarHeight() + m_nTabAreaHeight; + DWORD dwStyle = this->m_TabCtrl.GetStyle(); + if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) + { + m_Margins.cyTopHeight = rebar.GetBarHeight(); + if( m_bTabsVisible ) + { + m_Margins.cyBottomHeight = m_nTabAreaHeight; + if (m_bStatusBarVisible) + { + CRect rectStatusBar(0, 0, 0, 0); + ::GetWindowRect(m_hWndStatusBar, &rectStatusBar); + m_Margins.cyBottomHeight += rectStatusBar.Height(); + } + } + else + { + m_Margins.cyBottomHeight = 0; + } + } + else + { + m_Margins.cyTopHeight = rebar.GetBarHeight() + m_nTabAreaHeight; + m_Margins.cyBottomHeight = 0; + } SetTransparency(); } diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index d90600a9..deb9ff31 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -366,6 +366,7 @@ ControlsSettings::ControlsSettings() , bShowStatusbar(true) , bShowTabs(true) , bHideSingleTab(false) +, bTabsBottom(false) , bShowScrollbars(true) , bFlatScrollbars(false) { @@ -387,6 +388,7 @@ bool ControlsSettings::Load(const CComPtr& pSettingsRoot) XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"show_statusbar"), bShowStatusbar, true); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"show_tabs"), bShowTabs, true); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"hide_single_tab"), bHideSingleTab, false); + XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"tabs_bottom"), bTabsBottom, false); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"show_scrollbars"), bShowScrollbars, true); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"flat_scrollbars"), bFlatScrollbars, false); @@ -409,6 +411,7 @@ bool ControlsSettings::Save(const CComPtr& pSettingsRoot) XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"show_statusbar"), bShowStatusbar); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"show_tabs"), bShowTabs); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"hide_single_tab"), bHideSingleTab); + XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"tabs_bottom"), bTabsBottom); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"show_scrollbars"), bShowScrollbars); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"flat_scrollbars"), bFlatScrollbars); @@ -427,6 +430,7 @@ ControlsSettings& ControlsSettings::operator=(const ControlsSettings& other) bShowStatusbar = other.bShowStatusbar; bShowTabs = other.bShowTabs; bHideSingleTab = other.bHideSingleTab; + bTabsBottom = other.bTabsBottom; bShowScrollbars = other.bShowScrollbars; bFlatScrollbars = other.bFlatScrollbars; diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index 19ad86df..d8cfd1df 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -136,6 +136,7 @@ struct ControlsSettings bool bShowStatusbar; bool bShowTabs; bool bHideSingleTab; + bool bTabsBottom; bool bShowScrollbars; bool bFlatScrollbars; }; diff --git a/Console/resource.h b/Console/resource.h index acf7b0e1..7a08895a 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -1,248 +1,249 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Console.rc -// -#define IDR_POPUP_MENU_TAB 4 -#define IDD_ABOUTBOX 100 -#define IDR_MAINFRAME 128 -#define IDS_TAB_CREATE_FAILED 129 -#define IDI_ICON1 203 -#define IDD_RENAME_TAB 204 -#define IDD_SETTINGS_MAIN 205 -#define IDD_SETTINGS_CONSOLE 206 -#define IDD_SETTINGS_APPEARANCE 207 -#define IDD_SETTINGS_HOTKEYS 208 -#define IDD_SETTINGS_TRANSPARENCY 209 -#define IDD_SETTINGS_STYLES 209 -#define IDD_SETTINGS_TEMP 210 -#define IDD_SETTINGS_TABS 211 -#define IDD_SETTINGS_BEHAVIOR 212 -#define IDD_SETTINGS_TABS_1 213 -#define IDD_SETTINGS_TABS_2 214 -#define IDD_SETTINGS_MOUSE 215 -#define IDC_TAB_NAME 1000 -#define IDC_APPLY 1001 -#define IDC_TREE_SECTIONS 1002 -#define IDC_CHILD_PLACEHOLDER 1003 -#define IDC_CHANGE_REFRESH 1005 -#define IDC_REFRESH 1006 -#define IDC_ROWS 1007 -#define IDC_COLUMNS 1008 -#define IDC_BUFFER_ROWS 1010 -#define IDC_BUFFER_COLUMNS 1011 -#define IDC_SHELL 1012 -#define IDC_BUFFER_ROWS2 1012 -#define IDC_INIT_DIR 1013 -#define IDC_BUFFER_COLUMNS2 1013 -#define IDC_BTN_BROWSE_SHELL 1015 -#define IDC_BTN_BROWSE_DIR 1016 -#define IDC_CLR_00 1017 -#define IDC_BTN_BROWSE_BK 1017 -#define IDC_CLR_01 1018 -#define IDC_CLR_02 1019 -#define IDC_CLR_03 1020 -#define IDC_CLR_04 1021 -#define IDC_CLR_05 1022 -#define IDC_CLR_06 1023 -#define IDC_CLR_07 1024 -#define IDC_CLR_08 1025 -#define IDC_CLR_09 1026 -#define IDC_CLR_10 1027 -#define IDC_CLR_11 1028 -#define IDC_CLR_12 1029 -#define IDC_CLR_13 1030 -#define IDC_CLR_14 1031 -#define IDC_CLR_15 1032 -#define IDC_DEF_00 1033 -#define IDC_DEF_01 1034 -#define IDC_DEF_02 1035 -#define IDC_DEF_03 1036 -#define IDC_DEF_04 1037 -#define IDC_DEF_05 1038 -#define IDC_DEF_06 1039 -#define IDC_DEF_07 1040 -#define IDC_DEF_08 1041 -#define IDC_DEF_09 1042 -#define IDC_DEF_10 1043 -#define IDC_DEF_11 1044 -#define IDC_DEF_12 1045 -#define IDC_DEF_13 1046 -#define IDC_DEF_14 1047 -#define IDC_DEF_15 1048 -#define IDC_FONT 1049 -#define IDC_BTN_BROWSE_FONT 1050 -#define IDC_FONT_SIZE 1051 -#define IDC_SPIN_FONT_SIZE 1052 -#define IDC_CHECK_BOLD 1053 -#define IDC_CHECK_ITALIC 1054 -#define IDC_ACTIVE_ALPHA 1055 -#define IDC_SPIN_INSIDE_BORDER 1056 -#define IDC_INACTIVE_ALPHA 1057 -#define IDC_SPIN_CHANGE_REFRESH 1058 -#define IDC_SPIN_REFRESH 1059 -#define IDC_BTN_BROWSE_ICON 1060 -#define IDC_SPIN_ROWS 1061 -#define IDC_SPIN_BUFFER_ROWS 1062 -#define IDC_SPIN_COLUMNS 1063 -#define IDC_SPIN_BUFFER_COLUMNS 1064 -#define IDC_BTN_RESET_COLORS 1065 -#define IDC_SPIN_BUFFER_ROWS2 1065 -#define IDC_STATIC_ACTIVE_ALPHA 1066 -#define IDC_SPIN_BUFFER_COLUMNS2 1066 -#define IDC_STATIC_INACTIVE_ALPHA 1067 -#define IDC_TRANSPARENCY_TYPE 1068 -#define IDC_TRANSPARENCY_TYPE2 1069 -#define IDC_TRANSPARENCY_TYPE3 1070 -#define IDC_TRANSPARENCY_TYPE4 1071 -#define IDC_KEY_COLOR 1072 -#define IDC_STATIC_ACTIVE_WINDOW 1073 -#define IDC_STATIC_INACTIVE_WINDOW 1074 -#define IDC_STATIC_KEY_COLOR 1075 -#define IDC_LIST_HOTKEYS 1076 -#define IDC_BTN_ASSIGN 1077 -#define IDC_EDIT_HOTKEY 1078 -#define IDC_EDIT_COMMAND 1079 -#define IDC_KEY_COLOR2 1079 -#define IDC_SELECTION_COLOR 1079 -#define IDC_BTN_CLEAR 1080 -#define IDC_FONT_COLOR 1081 -#define IDC_CHECK_USE_COLOR 1082 -#define IDC_CHECK_SHOW_MENU 1083 -#define IDC_CHECK_SHOW_TOOLBAR 1084 -#define IDC_CHECK_SHOW_STATUS 1085 -#define IDC_CHECK_SHOW_TABS 1086 -#define IDC_CHECK_STYLE_CAPTION 1087 -#define IDC_CHECK_STYLE_RESIZABLE 1088 -#define IDC_CHECK_STYLE_TASKBAR 1089 -#define IDC_CHECK_STYLE_BORDER 1090 -#define IDC_INSIDE_BORDER 1091 -#define IDC_POS_X 1092 -#define IDC_CHECK_HIDE_SINGLE_TAB 1092 -#define IDC_CHECK_STYLE_TRAY 1093 -#define IDC_POS_Y 1094 -#define IDC_CHECK_HIDE_SCROLLBARS 1094 -#define IDC_CHECK_SHOW_SCROLLBARS 1094 -#define IDC_RADIO_DOCK_NONE 1095 -#define IDC_CHECK_SHOW_SCROLLBARS2 1095 -#define IDC_CHECK_FLAT_SCROLLBARS 1095 -#define IDC_RADIO_DOCK_TL 1096 -#define IDC_RADIO_DOCK_TR 1097 -#define IDC_RADIO_DOCK_BL 1098 -#define IDC_RADIO_DOCK_BR 1099 -#define IDC_RADIO_Z_REGULAR 1100 -#define IDC_TRIM_TAB_TITLES 1101 -#define IDC_RADIO_Z_BOTTOM 1102 -#define IDC_RADIO_Z_ONTOP 1103 -#define IDC_SNAP 1104 -#define IDC_CHECK_POSITION 1105 -#define IDC_CHECK_SNAP 1106 -#define IDC_SPIN_X 1107 -#define IDC_SPIN_Y 1108 -#define IDC_SPIN_SNAP 1109 -#define IDC_WINDOW_TITLE 1110 -#define IDC_WINDOW_ICON 1111 -#define IDC_CHECK_USE_TAB_TITLE 1112 -#define IDC_CHECK_USE_TAB_ICON 1113 -#define IDC_CHECK_SHOW_COMMAND 1114 -#define IDC_CHECK_SHOW_COMMAND_TABS 1115 -#define IDC_LIST_TABS 1116 -#define IDC_SPIN_Y2 1116 -#define IDC_SPIN_TRIM_TAB_TITLES 1116 -#define IDC_TAB_TITLE 1117 -#define IDC_TAB_ICON 1118 -#define IDC_RADIO_Z_DESKTOP 1118 -#define IDC_TAB_SHELL 1119 -#define IDC_TAB_INIT_DIR 1120 -#define IDC_COMBO_CURSOR 1121 -#define IDC_CURSOR_COLOR 1122 -#define IDC_RADIO_BK_TYPE 1123 -#define IDC_RADIO_BK_TYPE2 1124 -#define IDC_RADIO_BK_TYPE3 1125 -#define IDC_BK_COLOR 1126 -#define IDC_BK_IMAGE 1127 -#define IDC_CHECK_BK_RELATIVE 1128 -#define IDC_CHECK_BK_EXTEND 1129 -#define IDC_COMBO_BK_POS 1130 -#define IDC_TINT_COLOR 1131 -#define IDC_TINT_OPACITY 1132 -#define IDC_STATIC_TINT_OPACITY 1133 -#define IDC_BTN_ADD 1134 -#define IDC_BTN_UP 1135 -#define IDC_BTN_DOWN 1136 -#define IDC_BTN_DELETE 1137 -#define IDC_STATIC_BK_COLOR 1138 -#define IDC_STATIC_TINT_COLOR 1139 -#define IDC_STATIC_BK_IMAGE 1140 -#define IDC_STATIC_BK_POS 1141 -#define IDC_TINT_OPACITY_VAL 1142 -#define IDC_CHECK_COPY_ON_SELECT 1143 -#define IDC_CHECK_NO_WRAP 1144 -#define IDC_TAB1 1144 -#define IDC_CHECK_TRIM_SPACES 1145 -#define IDC_CHECK1 1145 -#define IDC_CHECK_DRAG_ON 1146 -#define IDC_TABS 1146 -#define IDC_CHECK_CLEAR_ON_COPY 1146 -#define IDC_CHECK_INVERSE_SHIFT 1147 -#define IDC_CHECK_USE_CONSOLE_TITLE 1147 -#define IDC_CHECK_TRIM_TAB_TITLES 1148 -#define IDC_STATIC_TRIM_CHARS 1149 -#define IDC_PAGE_SCROLL 1150 -#define IDC_PAGE_SCROLL2 1151 -#define IDC_SCROLL_PAGE_ROWS 1152 -#define IDC_SPIN_SCROLL_PAGE_ROWS 1153 -#define IDC_STATIC_ROWS 1154 -#define IDC_STATIC_VERSION 1155 -#define IDC_TAB_FLASHES 1155 -#define IDC_CHECK_SAVE_POSITION 1156 -#define IDC_SPIN_TAB_FLASHES 1156 -#define IDC_CHECK_SAVE_SIZE 1157 -#define IDC_CHECK_USE_SCROLL_LOCK 1158 -#define IDPANE_ROWS_COLUMNS 1159 -#define IDC_LIST_MOUSE_COMMANDS 1160 -#define IDC_COMBO_BUTTONS 1161 -#define IDC_CHECK_CTRL 1162 -#define IDC_CHECK_SHIFT 1163 -#define IDC_CHECK_USER_DATA_DIR 1163 -#define IDC_CHECK_ALT 1164 -#define IDC_RADIO_COPY_NEWLINE_CHAR 1164 -#define IDC_RADIO2 1165 -#define IDC_COMBO_DOCKING 1167 -#define IDC_COMBO_ZORDER 1168 -#define IDC_CHECK_FLASH_TAB 1168 -#define IDC_COMBO_SMOOTHING 1169 -#define IDC_CHECK_LEAVE_HIGHLIGHTED 1170 -#define IDC_CHECK_START_HIDDEN 1171 -#define IDC_RADIO1 1172 -#define IDC_APPTEXT 1173 -#define IDC_APPICON 1174 -#define ID_RENAME_TAB_OK 1175 -#define ID_NEW_TAB_1 2000 -#define ID_SWITCH_TAB_1 2100 -#define ID_NEXT_TAB 2200 -#define ID_PREV_TAB 2201 -#define IDC_DUMP_BUFFER 3000 -#define ID_FILE_NEW_TAB 32775 -#define ID_VIEW_CONSOLE 32777 -#define ID_FILE_CLOSE_TAB 32779 -#define ID_EDIT_RENAME_TAB 32781 -#define ID_EDIT_SETTINGS 32783 -#define ID_VIEW_MENU 32784 -#define ID__EDIT 32786 -#define ID__VIEW 32787 -#define ID__HELP 32788 -#define ID_VIEW_TABS 32789 -#define ID_EDIT_CLEAR_SELECTION 32791 -#define ID_EDIT_STOPSCROLLING 32792 -#define ID_EDIT_STOP_SCROLLING 32793 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 222 -#define _APS_NEXT_COMMAND_VALUE 32794 -#define _APS_NEXT_CONTROL_VALUE 1176 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Console.rc +// +#define IDR_POPUP_MENU_TAB 4 +#define IDD_ABOUTBOX 100 +#define IDR_MAINFRAME 128 +#define IDS_TAB_CREATE_FAILED 129 +#define IDI_ICON1 203 +#define IDD_RENAME_TAB 204 +#define IDD_SETTINGS_MAIN 205 +#define IDD_SETTINGS_CONSOLE 206 +#define IDD_SETTINGS_APPEARANCE 207 +#define IDD_SETTINGS_HOTKEYS 208 +#define IDD_SETTINGS_TRANSPARENCY 209 +#define IDD_SETTINGS_STYLES 209 +#define IDD_SETTINGS_TEMP 210 +#define IDD_SETTINGS_TABS 211 +#define IDD_SETTINGS_BEHAVIOR 212 +#define IDD_SETTINGS_TABS_1 213 +#define IDD_SETTINGS_TABS_2 214 +#define IDD_SETTINGS_MOUSE 215 +#define IDC_TAB_NAME 1000 +#define IDC_APPLY 1001 +#define IDC_TREE_SECTIONS 1002 +#define IDC_CHILD_PLACEHOLDER 1003 +#define IDC_CHANGE_REFRESH 1005 +#define IDC_REFRESH 1006 +#define IDC_ROWS 1007 +#define IDC_COLUMNS 1008 +#define IDC_BUFFER_ROWS 1010 +#define IDC_BUFFER_COLUMNS 1011 +#define IDC_SHELL 1012 +#define IDC_BUFFER_ROWS2 1012 +#define IDC_INIT_DIR 1013 +#define IDC_BUFFER_COLUMNS2 1013 +#define IDC_BTN_BROWSE_SHELL 1015 +#define IDC_BTN_BROWSE_DIR 1016 +#define IDC_CLR_00 1017 +#define IDC_BTN_BROWSE_BK 1017 +#define IDC_CLR_01 1018 +#define IDC_CLR_02 1019 +#define IDC_CLR_03 1020 +#define IDC_CLR_04 1021 +#define IDC_CLR_05 1022 +#define IDC_CLR_06 1023 +#define IDC_CLR_07 1024 +#define IDC_CLR_08 1025 +#define IDC_CLR_09 1026 +#define IDC_CLR_10 1027 +#define IDC_CLR_11 1028 +#define IDC_CLR_12 1029 +#define IDC_CLR_13 1030 +#define IDC_CLR_14 1031 +#define IDC_CLR_15 1032 +#define IDC_DEF_00 1033 +#define IDC_DEF_01 1034 +#define IDC_DEF_02 1035 +#define IDC_DEF_03 1036 +#define IDC_DEF_04 1037 +#define IDC_DEF_05 1038 +#define IDC_DEF_06 1039 +#define IDC_DEF_07 1040 +#define IDC_DEF_08 1041 +#define IDC_DEF_09 1042 +#define IDC_DEF_10 1043 +#define IDC_DEF_11 1044 +#define IDC_DEF_12 1045 +#define IDC_DEF_13 1046 +#define IDC_DEF_14 1047 +#define IDC_DEF_15 1048 +#define IDC_FONT 1049 +#define IDC_BTN_BROWSE_FONT 1050 +#define IDC_FONT_SIZE 1051 +#define IDC_SPIN_FONT_SIZE 1052 +#define IDC_CHECK_BOLD 1053 +#define IDC_CHECK_ITALIC 1054 +#define IDC_ACTIVE_ALPHA 1055 +#define IDC_SPIN_INSIDE_BORDER 1056 +#define IDC_INACTIVE_ALPHA 1057 +#define IDC_SPIN_CHANGE_REFRESH 1058 +#define IDC_SPIN_REFRESH 1059 +#define IDC_BTN_BROWSE_ICON 1060 +#define IDC_SPIN_ROWS 1061 +#define IDC_SPIN_BUFFER_ROWS 1062 +#define IDC_SPIN_COLUMNS 1063 +#define IDC_SPIN_BUFFER_COLUMNS 1064 +#define IDC_BTN_RESET_COLORS 1065 +#define IDC_SPIN_BUFFER_ROWS2 1065 +#define IDC_STATIC_ACTIVE_ALPHA 1066 +#define IDC_SPIN_BUFFER_COLUMNS2 1066 +#define IDC_STATIC_INACTIVE_ALPHA 1067 +#define IDC_TRANSPARENCY_TYPE 1068 +#define IDC_TRANSPARENCY_TYPE2 1069 +#define IDC_TRANSPARENCY_TYPE3 1070 +#define IDC_TRANSPARENCY_TYPE4 1071 +#define IDC_KEY_COLOR 1072 +#define IDC_STATIC_ACTIVE_WINDOW 1073 +#define IDC_STATIC_INACTIVE_WINDOW 1074 +#define IDC_STATIC_KEY_COLOR 1075 +#define IDC_LIST_HOTKEYS 1076 +#define IDC_BTN_ASSIGN 1077 +#define IDC_EDIT_HOTKEY 1078 +#define IDC_EDIT_COMMAND 1079 +#define IDC_KEY_COLOR2 1079 +#define IDC_SELECTION_COLOR 1079 +#define IDC_BTN_CLEAR 1080 +#define IDC_FONT_COLOR 1081 +#define IDC_CHECK_USE_COLOR 1082 +#define IDC_CHECK_SHOW_MENU 1083 +#define IDC_CHECK_SHOW_TOOLBAR 1084 +#define IDC_CHECK_SHOW_STATUS 1085 +#define IDC_CHECK_SHOW_TABS 1086 +#define IDC_CHECK_STYLE_CAPTION 1087 +#define IDC_CHECK_STYLE_RESIZABLE 1088 +#define IDC_CHECK_STYLE_TASKBAR 1089 +#define IDC_CHECK_STYLE_BORDER 1090 +#define IDC_INSIDE_BORDER 1091 +#define IDC_POS_X 1092 +#define IDC_CHECK_HIDE_SINGLE_TAB 1092 +#define IDC_CHECK_STYLE_TRAY 1093 +#define IDC_POS_Y 1094 +#define IDC_CHECK_HIDE_SCROLLBARS 1094 +#define IDC_CHECK_SHOW_SCROLLBARS 1094 +#define IDC_RADIO_DOCK_NONE 1095 +#define IDC_CHECK_SHOW_SCROLLBARS2 1095 +#define IDC_CHECK_FLAT_SCROLLBARS 1095 +#define IDC_RADIO_DOCK_TL 1096 +#define IDC_CHECK_TABS_BOTTOM 1096 +#define IDC_RADIO_DOCK_TR 1097 +#define IDC_RADIO_DOCK_BL 1098 +#define IDC_RADIO_DOCK_BR 1099 +#define IDC_RADIO_Z_REGULAR 1100 +#define IDC_TRIM_TAB_TITLES 1101 +#define IDC_RADIO_Z_BOTTOM 1102 +#define IDC_RADIO_Z_ONTOP 1103 +#define IDC_SNAP 1104 +#define IDC_CHECK_POSITION 1105 +#define IDC_CHECK_SNAP 1106 +#define IDC_SPIN_X 1107 +#define IDC_SPIN_Y 1108 +#define IDC_SPIN_SNAP 1109 +#define IDC_WINDOW_TITLE 1110 +#define IDC_WINDOW_ICON 1111 +#define IDC_CHECK_USE_TAB_TITLE 1112 +#define IDC_CHECK_USE_TAB_ICON 1113 +#define IDC_CHECK_SHOW_COMMAND 1114 +#define IDC_CHECK_SHOW_COMMAND_TABS 1115 +#define IDC_LIST_TABS 1116 +#define IDC_SPIN_Y2 1116 +#define IDC_SPIN_TRIM_TAB_TITLES 1116 +#define IDC_TAB_TITLE 1117 +#define IDC_TAB_ICON 1118 +#define IDC_RADIO_Z_DESKTOP 1118 +#define IDC_TAB_SHELL 1119 +#define IDC_TAB_INIT_DIR 1120 +#define IDC_COMBO_CURSOR 1121 +#define IDC_CURSOR_COLOR 1122 +#define IDC_RADIO_BK_TYPE 1123 +#define IDC_RADIO_BK_TYPE2 1124 +#define IDC_RADIO_BK_TYPE3 1125 +#define IDC_BK_COLOR 1126 +#define IDC_BK_IMAGE 1127 +#define IDC_CHECK_BK_RELATIVE 1128 +#define IDC_CHECK_BK_EXTEND 1129 +#define IDC_COMBO_BK_POS 1130 +#define IDC_TINT_COLOR 1131 +#define IDC_TINT_OPACITY 1132 +#define IDC_STATIC_TINT_OPACITY 1133 +#define IDC_BTN_ADD 1134 +#define IDC_BTN_UP 1135 +#define IDC_BTN_DOWN 1136 +#define IDC_BTN_DELETE 1137 +#define IDC_STATIC_BK_COLOR 1138 +#define IDC_STATIC_TINT_COLOR 1139 +#define IDC_STATIC_BK_IMAGE 1140 +#define IDC_STATIC_BK_POS 1141 +#define IDC_TINT_OPACITY_VAL 1142 +#define IDC_CHECK_COPY_ON_SELECT 1143 +#define IDC_CHECK_NO_WRAP 1144 +#define IDC_TAB1 1144 +#define IDC_CHECK_TRIM_SPACES 1145 +#define IDC_CHECK1 1145 +#define IDC_CHECK_DRAG_ON 1146 +#define IDC_TABS 1146 +#define IDC_CHECK_CLEAR_ON_COPY 1146 +#define IDC_CHECK_INVERSE_SHIFT 1147 +#define IDC_CHECK_USE_CONSOLE_TITLE 1147 +#define IDC_CHECK_TRIM_TAB_TITLES 1148 +#define IDC_STATIC_TRIM_CHARS 1149 +#define IDC_PAGE_SCROLL 1150 +#define IDC_PAGE_SCROLL2 1151 +#define IDC_SCROLL_PAGE_ROWS 1152 +#define IDC_SPIN_SCROLL_PAGE_ROWS 1153 +#define IDC_STATIC_ROWS 1154 +#define IDC_STATIC_VERSION 1155 +#define IDC_TAB_FLASHES 1155 +#define IDC_CHECK_SAVE_POSITION 1156 +#define IDC_SPIN_TAB_FLASHES 1156 +#define IDC_CHECK_SAVE_SIZE 1157 +#define IDC_CHECK_USE_SCROLL_LOCK 1158 +#define IDPANE_ROWS_COLUMNS 1159 +#define IDC_LIST_MOUSE_COMMANDS 1160 +#define IDC_COMBO_BUTTONS 1161 +#define IDC_CHECK_CTRL 1162 +#define IDC_CHECK_SHIFT 1163 +#define IDC_CHECK_USER_DATA_DIR 1163 +#define IDC_CHECK_ALT 1164 +#define IDC_RADIO_COPY_NEWLINE_CHAR 1164 +#define IDC_RADIO2 1165 +#define IDC_COMBO_DOCKING 1167 +#define IDC_COMBO_ZORDER 1168 +#define IDC_CHECK_FLASH_TAB 1168 +#define IDC_COMBO_SMOOTHING 1169 +#define IDC_CHECK_LEAVE_HIGHLIGHTED 1170 +#define IDC_CHECK_START_HIDDEN 1171 +#define IDC_RADIO1 1172 +#define IDC_APPTEXT 1173 +#define IDC_APPICON 1174 +#define ID_RENAME_TAB_OK 1175 +#define ID_NEW_TAB_1 2000 +#define ID_SWITCH_TAB_1 2100 +#define ID_NEXT_TAB 2200 +#define ID_PREV_TAB 2201 +#define IDC_DUMP_BUFFER 3000 +#define ID_FILE_NEW_TAB 32775 +#define ID_VIEW_CONSOLE 32777 +#define ID_FILE_CLOSE_TAB 32779 +#define ID_EDIT_RENAME_TAB 32781 +#define ID_EDIT_SETTINGS 32783 +#define ID_VIEW_MENU 32784 +#define ID__EDIT 32786 +#define ID__VIEW 32787 +#define ID__HELP 32788 +#define ID_VIEW_TABS 32789 +#define ID_EDIT_CLEAR_SELECTION 32791 +#define ID_EDIT_STOPSCROLLING 32792 +#define ID_EDIT_STOP_SCROLLING 32793 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 222 +#define _APS_NEXT_COMMAND_VALUE 32794 +#define _APS_NEXT_CONTROL_VALUE 1176 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif From 47f813e0eb9dc8cdd7ae9821207817b07fc3323f Mon Sep 17 00:00:00 2001 From: cbucher Date: Fri, 27 Aug 2010 18:39:49 +0200 Subject: [PATCH 005/207] synchro --- Console/Console.cpp | 4 +- Console/Console.rc | 71 ++++---- Console/ConsoleHandler.cpp | 6 +- Console/ConsoleHandler.h | 4 +- Console/ConsoleView.cpp | 118 +------------ Console/DlgSettingsStyles.cpp | 5 +- Console/DlgSettingsStyles.h | 4 +- Console/DlgSettingsTabs.cpp | 79 +-------- Console/DlgSettingsTabs.h | 1 - Console/MainFrame.cpp | 130 ++++++++------ Console/PageSettingsTabs1.cpp | 72 ++++++++ Console/PageSettingsTabs1.h | 13 +- Console/PageSettingsTabs2.cpp | 37 ++++ Console/PageSettingsTabs2.h | 5 +- Console/SettingsHandler.cpp | 11 +- Console/SettingsHandler.h | 17 +- Console/console.xml | 2 +- Console/resource.h | 13 +- ConsoleHook/ConsoleHandler.cpp | 306 ++++++--------------------------- ConsoleHook/ConsoleHandler.h | 6 +- shared/SharedMemNames.h | 6 +- 21 files changed, 338 insertions(+), 572 deletions(-) diff --git a/Console/Console.cpp b/Console/Console.cpp index dd56df74..f280a0b4 100644 --- a/Console/Console.cpp +++ b/Console/Console.cpp @@ -177,7 +177,7 @@ int Run(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWDEFAULT) if (!g_settingsHandler->LoadSettings(Helpers::ExpandEnvironmentStrings(strConfigFile))) { //TODO: error handling - return -1; + return 1; } // create main window @@ -192,7 +192,7 @@ int Run(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWDEFAULT) if(wndMain.CreateEx(noTaskbarParent.m_hWnd) == NULL) { ATLTRACE(_T("Main window creation failed!\n")); - return 0; + return 1; } wndMain.ShowWindow(nCmdShow); diff --git a/Console/Console.rc b/Console/Console.rc index c96b95d0..4c07b758 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -367,15 +367,15 @@ IDD_SETTINGS_STYLES DIALOGEX 0, 0, 226, 276 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "Show &menu",IDC_CHECK_SHOW_MENU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,12,53,10 - CONTROL "Show &toolbar",IDC_CHECK_SHOW_TOOLBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,24,58,10 - CONTROL "Sho&w status bar",IDC_CHECK_SHOW_STATUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,36,68,10 - CONTROL "Show t&abs",IDC_CHECK_SHOW_TABS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,48,49,10 - CONTROL "Hide &single tab",IDC_CHECK_HIDE_SINGLE_TAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,60,59,10 - CONTROL "Tabs &bottom *",IDC_CHECK_TABS_BOTTOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,73,59,10 - CONTROL "Show scro&llbars",IDC_CHECK_SHOW_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,85,72,10 - CONTROL "&Flat scrollbars",IDC_CHECK_FLAT_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,97,59,10 - GROUPBOX "Controls",IDC_STATIC,0,0,88,114 + CONTROL "Show &menu",IDC_CHECK_SHOW_MENU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,12,53,10 + CONTROL "Show &toolbar",IDC_CHECK_SHOW_TOOLBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,24,58,10 + CONTROL "Sho&w status bar",IDC_CHECK_SHOW_STATUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,36,68,10 + CONTROL "Show t&abs",IDC_CHECK_SHOW_TABS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,48,49,10 + CONTROL "Hide &single tab",IDC_CHECK_HIDE_SINGLE_TAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,60,59,10 + CONTROL "Tabs on bottom *",IDC_CHECK_TABS_ON_BOTTOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,71,70,10 + CONTROL "Show scro&llbars",IDC_CHECK_SHOW_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,83,72,10 + CONTROL "&Flat scrollbars",IDC_CHECK_FLAT_SCROLLBARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,95,59,10 + GROUPBOX "Controls",IDC_STATIC,0,0,92,111 CONTROL "&Caption *",IDC_CHECK_STYLE_CAPTION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,12,47,10 CONTROL "Resi&zable *",IDC_CHECK_STYLE_RESIZABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,24,52,10 CONTROL "Bo&rder *",IDC_CHECK_STYLE_BORDER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,36,43,10 @@ -384,22 +384,22 @@ BEGIN LTEXT "Inside &border:",IDC_STATIC,102,53,46,8 EDITTEXT IDC_INSIDE_BORDER,153,50,33,14,ES_AUTOHSCROLL CONTROL "",IDC_SPIN_INSIDE_BORDER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,191,50,11,14 - LTEXT "Selection col&or:",IDC_STATIC,102,74,50,8 - CONTROL "",IDC_SELECTION_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,153,71,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Styles",IDC_STATIC,92,0,134,114 - CONTROL "&None",IDC_TRANSPARENCY_TYPE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,8,114,33,10 - CONTROL "&Alpha",IDC_TRANSPARENCY_TYPE2,"Button",BS_AUTORADIOBUTTON,8,129,34,10 - CONTROL "Color &key",IDC_TRANSPARENCY_TYPE3,"Button",BS_AUTORADIOBUTTON,8,218,46,10 - CONTROL "Glass",IDC_TRANSPARENCY_TYPE4,"Button",BS_AUTORADIOBUTTON,50,129,34,10 - LTEXT "A&ctive window",IDC_STATIC_ACTIVE_WINDOW,19,142,47,8 - CONTROL "",IDC_ACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,153,185,22 - LTEXT "255",IDC_STATIC_ACTIVE_ALPHA,204,155,14,8,0,WS_EX_RIGHT - LTEXT "&Inactive window",IDC_STATIC_INACTIVE_WINDOW,19,177,53,8 - CONTROL "",IDC_INACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,190,185,22 - LTEXT "255",IDC_STATIC_INACTIVE_ALPHA,204,192,14,8,0,WS_EX_RIGHT - LTEXT "Key col&or:",IDC_STATIC_KEY_COLOR,19,235,33,8 - CONTROL "",IDC_KEY_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,54,232,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Window transparency",IDC_STATIC,0,114,226,162 + LTEXT "Selection col&or:",IDC_STATIC,102,84,50,8 + CONTROL "",IDC_SELECTION_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,153,81,16,14,WS_EX_DLGMODALFRAME + GROUPBOX "Styles",IDC_STATIC,96,0,130,111 + CONTROL "&None",IDC_TRANSPARENCY_TYPE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,8,124,33,10 + CONTROL "&Alpha",IDC_TRANSPARENCY_TYPE2,"Button",BS_AUTORADIOBUTTON,8,139,34,10 + CONTROL "Color &key",IDC_TRANSPARENCY_TYPE3,"Button",BS_AUTORADIOBUTTON,8,228,46,10 + CONTROL "Glass",IDC_TRANSPARENCY_TYPE4,"Button",BS_AUTORADIOBUTTON,50,139,34,10 + LTEXT "A&ctive window",IDC_STATIC_ACTIVE_WINDOW,19,152,47,8 + CONTROL "",IDC_ACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,163,185,22 + LTEXT "255",IDC_STATIC_ACTIVE_ALPHA,204,165,14,8,0,WS_EX_RIGHT + LTEXT "&Inactive window",IDC_STATIC_INACTIVE_WINDOW,19,187,53,8 + CONTROL "",IDC_INACTIVE_ALPHA,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,19,200,185,22 + LTEXT "255",IDC_STATIC_INACTIVE_ALPHA,204,202,14,8,0,WS_EX_RIGHT + LTEXT "Key col&or:",IDC_STATIC_KEY_COLOR,19,245,33,8 + CONTROL "",IDC_KEY_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,54,242,16,14,WS_EX_DLGMODALFRAME + GROUPBOX "Window transparency",IDC_STATIC,0,111,226,154 END IDD_SETTINGS_TEMP DIALOGEX 0, 0, 611, 555 @@ -480,6 +480,7 @@ BEGIN LTEXT "Icon:",-1,8,34,18,8 EDITTEXT IDC_TAB_ICON,28,31,105,14,ES_AUTOHSCROLL PUSHBUTTON "...",IDC_BTN_BROWSE_ICON,136,31,15,14 + CONTROL "Use default",IDC_CHECK_DEFAULT_ICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,33,53,10 LTEXT "S&hell:",-1,7,71,23,8 EDITTEXT IDC_TAB_SHELL,46,68,145,14,ES_AUTOHSCROLL PUSHBUTTON "...",IDC_BTN_BROWSE_SHELL,193,68,15,14 @@ -492,7 +493,7 @@ BEGIN LTEXT "Col&or:",-1,5,141,20,8 CONTROL "",IDC_CURSOR_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,28,138,16,14,WS_EX_DLGMODALFRAME GROUPBOX "Cursor",-1,0,107,120,53,0,WS_EX_TRANSPARENT - GROUPBOX "Title && icon",-1,0,3,160,50,0,WS_EX_TRANSPARENT + GROUPBOX "Title && icon",-1,0,3,217,50,0,WS_EX_TRANSPARENT END IDD_SETTINGS_TABS_2 DIALOGEX 0, 0, 223, 172 @@ -594,17 +595,16 @@ BEGIN IDD_SETTINGS_STYLES, DIALOG BEGIN - VERTGUIDE, 10 - BOTTOMMARGIN, 254 + VERTGUIDE, 6 HORZGUIDE, 17 HORZGUIDE, 29 HORZGUIDE, 41 HORZGUIDE, 53 HORZGUIDE, 65 - HORZGUIDE, 78 - HORZGUIDE, 90 - HORZGUIDE, 102 - HORZGUIDE, 114 + HORZGUIDE, 76 + HORZGUIDE, 88 + HORZGUIDE, 100 + HORZGUIDE, 111 END IDD_SETTINGS_TEMP, DIALOG @@ -638,7 +638,9 @@ BEGIN IDD_SETTINGS_TABS_1, DIALOG BEGIN + VERTGUIDE, 217 HORZGUIDE, 20 + HORZGUIDE, 38 HORZGUIDE, 72 HORZGUIDE, 87 HORZGUIDE, 124 @@ -859,7 +861,7 @@ END STRINGTABLE BEGIN ID_VIEW_MENU "Show or hide the menu" - ID_VIEW_TABS "Show or hide the status tabs" + ID_VIEW_TABS "Show or hide the tabs" END STRINGTABLE @@ -917,7 +919,8 @@ END // // Generated from the TEXTINCLUDE 3 resource. // - + + ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 4a920fdd..9131e9cc 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -31,7 +31,7 @@ ConsoleHandler::ConsoleHandler() , m_consoleInfo() , m_consoleBuffer() , m_consoleCopyInfo() -, m_consolePasteInfo() +, m_consoleTextInfo() , m_consoleMouseEvent() , m_newConsoleSize() , m_newScrollPos() @@ -345,8 +345,8 @@ bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId) // copy info m_consoleCopyInfo.Create((SharedMemNames::formatCopyInfo % dwConsoleProcessId).str(), 1, syncObjBoth); - // paste info (used for pasting and sending text to console) - m_consolePasteInfo.Create((SharedMemNames::formatPasteInfo % dwConsoleProcessId).str(), 1, syncObjBoth); + // text info (used for sending text to console) + m_consoleTextInfo.Create((SharedMemNames::formatTextInfo % dwConsoleProcessId).str(), 1, syncObjBoth); // mouse event m_consoleMouseEvent.Create((SharedMemNames::formatMouseEvent % dwConsoleProcessId).str(), 1, syncObjBoth); diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index 0f8529aa..d33acd68 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -34,7 +34,7 @@ class ConsoleHandler SharedMemory& GetCursorInfo() { return m_cursorInfo; } SharedMemory& GetConsoleBuffer() { return m_consoleBuffer; } SharedMemory& GetCopyInfo() { return m_consoleCopyInfo; } - SharedMemory& GetPasteInfo() { return m_consolePasteInfo; } + SharedMemory& GetTextInfo() { return m_consoleTextInfo; } SharedMemory& GetNewConsoleSize() { return m_newConsoleSize; } SharedMemory& GetNewScrollPos() { return m_newScrollPos; } @@ -74,7 +74,7 @@ class ConsoleHandler SharedMemory m_cursorInfo; SharedMemory m_consoleBuffer; SharedMemory m_consoleCopyInfo; - SharedMemory m_consolePasteInfo; + SharedMemory m_consoleTextInfo; SharedMemory m_consoleMouseEvent; SharedMemory m_newConsoleSize; diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index cb35e29e..b0cf632a 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -770,7 +770,6 @@ LRESULT ConsoleView::OnDropFiles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/ } ::DragFinish(hDrop); - // TODO: fix this SendTextToConsole(strFilenames); return 0; } @@ -1251,21 +1250,6 @@ void ConsoleView::Paste() { if (!::IsClipboardFormatAvailable(CF_UNICODETEXT)) return; ::SendMessage(m_consoleHandler.GetConsoleParams()->hwndConsoleWindow, WM_SYSCOMMAND, SC_CONSOLE_PASTE, 0); - -/* - SharedMemory& pasteInfo = m_consoleHandler.GetPasteInfo(); - - { - SharedMemoryLock memLock(pasteInfo); - - pasteInfo = 0; - pasteInfo.SetReqEvent(); - } - - TRACE(L"Waiting for paste response event\n"); - ::WaitForSingleObject(pasteInfo.GetRespEvent(), INFINITE); - TRACE(L"Done waiting for paste response event\n"); - */ } ////////////////////////////////////////////////////////////////////////////// @@ -2057,108 +2041,16 @@ void ConsoleView::UpdateOffscreen(const CRect& rectBlit) void ConsoleView::SendTextToConsole(const wchar_t* pszText) { -/* - if (pszText == NULL) return; - - size_t textLen = wcslen(pszText); - - if (textLen == 0) return; - - size_t partLen = 256; - size_t parts = textLen/partLen; - - for (size_t part = 0; part < parts+1; ++part) - { - size_t offset = part*partLen; - - if (part == parts) - { - // last part, modify part size - partLen = textLen - parts*partLen; - } - - scoped_array kbdInputs(new INPUT[2*partLen]); - ::ZeroMemory(kbdInputs.get(), sizeof(INPUT_RECORD)*2*partLen); - - for (size_t i = 0; i < partLen; ++i, ++offset) - { - if ((pszText[offset] == L'\r') || (pszText[offset] == L'\n')) - { - kbdInputs[2*i].type = INPUT_KEYBOARD; - kbdInputs[2*i].ki.dwFlags = 0; - kbdInputs[2*i].ki.wVk = VK_RETURN; - - kbdInputs[2*i+1].type = INPUT_KEYBOARD; - kbdInputs[2*i+1].ki.dwFlags = KEYEVENTF_KEYUP; - kbdInputs[2*i+1].ki.wVk = VK_RETURN; - - if ((pszText[offset] == L'\r') && (pszText[offset+1] == L'\n')) ++offset; - - ::SendInput(2, kbdInputs.get() + 2*i, sizeof(INPUT)); - } - else - { - kbdInputs[2*i].type = INPUT_KEYBOARD; - kbdInputs[2*i].ki.dwFlags = KEYEVENTF_UNICODE; - kbdInputs[2*i].ki.wScan = pszText[offset]; - - kbdInputs[2*i+1].type = INPUT_KEYBOARD; - kbdInputs[2*i+1].ki.dwFlags = KEYEVENTF_UNICODE|KEYEVENTF_KEYUP; - kbdInputs[2*i+1].ki.wVk = pszText[offset]; - - ::SendInput(2, kbdInputs.get() + 2*i, sizeof(INPUT)); - } - } - -// ::SendInput(2*partLen, kbdInputs.get(), sizeof(INPUT)); - } -*/ - - - -/* - INPUT inp[2]; - - for (size_t i = 0; i < textLen; ++i) - { - if ((pszText[i] == L'\r') || (pszText[i] == L'\n')) - { - memset(inp,0,sizeof(INPUT)); - inp[0].type = INPUT_KEYBOARD; - inp[0].ki.dwFlags = 0; // to avoid shift, and so on - inp[1] = inp[0]; - inp[1].ki.dwFlags |= KEYEVENTF_KEYUP; - - inp[0].ki.wVk = inp[1].ki.wVk = VK_RETURN; - ::SendInput(2, inp, sizeof(INPUT)); - - if ((pszText[i] == L'\r') && (pszText[i+1] == L'\n')) ++i; - } - else - { - memset(inp,0,sizeof(INPUT)); - inp[0].type = INPUT_KEYBOARD; - inp[0].ki.dwFlags = KEYEVENTF_UNICODE; // to avoid shift, and so on - inp[1] = inp[0]; - inp[1].ki.dwFlags |= KEYEVENTF_KEYUP; - - inp[0].ki.wScan = inp[1].ki.wScan = pszText[i]; - ::SendInput(2, inp, sizeof(INPUT)); - } - - } -*/ - if (pszText == NULL) return; size_t textLen = wcslen(pszText); if (textLen == 0) return; - SharedMemory& pasteInfo = m_consoleHandler.GetPasteInfo(); + SharedMemory& textInfo = m_consoleHandler.GetTextInfo(); { - SharedMemoryLock memLock(pasteInfo); + SharedMemoryLock memLock(textInfo); void* pRemoteMemory = ::VirtualAllocEx( m_consoleHandler.GetConsoleHandle().get(), @@ -2180,11 +2072,11 @@ void ConsoleView::SendTextToConsole(const wchar_t* pszText) return; } - pasteInfo = reinterpret_cast(pRemoteMemory); - pasteInfo.SetReqEvent(); + textInfo = reinterpret_cast(pRemoteMemory); + textInfo.SetReqEvent(); } - ::WaitForSingleObject(pasteInfo.GetRespEvent(), INFINITE); + ::WaitForSingleObject(textInfo.GetRespEvent(), INFINITE); } ///////////////////////////////////////////////////////////////////////////// diff --git a/Console/DlgSettingsStyles.cpp b/Console/DlgSettingsStyles.cpp index 72b3951a..a5c70a09 100644 --- a/Console/DlgSettingsStyles.cpp +++ b/Console/DlgSettingsStyles.cpp @@ -40,7 +40,7 @@ LRESULT DlgSettingsStyles::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM m_nShowStatusbar= m_controlsSettings.bShowStatusbar ? 1 : 0; m_nShowTabs = m_controlsSettings.bShowTabs ? 1 : 0; m_nHideSingleTab= m_controlsSettings.bHideSingleTab ? 1 : 0; - m_nTabsBottom = m_controlsSettings.bTabsBottom ? 1 : 0; + m_nTabsOnBottom = m_controlsSettings.bTabsOnBottom ? 1 : 0; m_nShowScrollbars= m_controlsSettings.bShowScrollbars ? 1 : 0; m_nFlatScrollbars= m_controlsSettings.bFlatScrollbars ? 1 : 0; @@ -141,7 +141,7 @@ LRESULT DlgSettingsStyles::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWn m_controlsSettings.bShowStatusbar = (m_nShowStatusbar > 0); m_controlsSettings.bShowTabs = (m_nShowTabs > 0); m_controlsSettings.bHideSingleTab = (m_nHideSingleTab > 0); - m_controlsSettings.bTabsBottom = (m_nTabsBottom > 0); + m_controlsSettings.bTabsOnBottom = (m_nTabsOnBottom > 0); m_controlsSettings.bShowScrollbars = (m_nShowScrollbars > 0); m_controlsSettings.bFlatScrollbars = (m_nFlatScrollbars > 0); @@ -284,6 +284,7 @@ void DlgSettingsStyles::EnableTabControls() if (m_nShowTabs > 0) { GetDlgItem(IDC_CHECK_HIDE_SINGLE_TAB).EnableWindow(); + GetDlgItem(IDC_CHECK_TABS_ON_BOTTOM).EnableWindow(); } } diff --git a/Console/DlgSettingsStyles.h b/Console/DlgSettingsStyles.h index 6fc1af28..1f296b1e 100644 --- a/Console/DlgSettingsStyles.h +++ b/Console/DlgSettingsStyles.h @@ -26,7 +26,7 @@ class DlgSettingsStyles DDX_CHECK(IDC_CHECK_SHOW_STATUS, m_nShowStatusbar) DDX_CHECK(IDC_CHECK_SHOW_TABS, m_nShowTabs) DDX_CHECK(IDC_CHECK_HIDE_SINGLE_TAB, m_nHideSingleTab) - DDX_CHECK(IDC_CHECK_TABS_BOTTOM, m_nTabsBottom) + DDX_CHECK(IDC_CHECK_TABS_ON_BOTTOM, m_nTabsOnBottom) DDX_CHECK(IDC_CHECK_SHOW_SCROLLBARS, m_nShowScrollbars) DDX_CHECK(IDC_CHECK_FLAT_SCROLLBARS, m_nFlatScrollbars) DDX_CHECK(IDC_CHECK_STYLE_CAPTION, m_nShowCaption) @@ -85,7 +85,7 @@ class DlgSettingsStyles int m_nShowStatusbar; int m_nShowTabs; int m_nHideSingleTab; - int m_nTabsBottom; + int m_nTabsOnBottom; int m_nShowScrollbars; int m_nFlatScrollbars; diff --git a/Console/DlgSettingsTabs.cpp b/Console/DlgSettingsTabs.cpp index 9857c507..4cebd940 100644 --- a/Console/DlgSettingsTabs.cpp +++ b/Console/DlgSettingsTabs.cpp @@ -83,7 +83,7 @@ LRESULT DlgSettingsTabs::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM / LRESULT DlgSettingsTabs::OnTabTitleChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { - m_listCtrl.SetItemText(m_listCtrl.GetSelectedIndex(), 0, m_page1.m_strTitle); + m_listCtrl.SetItemText(m_listCtrl.GetSelectedIndex(), 0, m_page1.GetTabTitle()); return 0; } @@ -96,12 +96,10 @@ LRESULT DlgSettingsTabs::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndC { if (wID == IDOK) { - TabData* pTabData = reinterpret_cast(m_listCtrl.GetItemData(m_listCtrl.GetSelectedIndex())); + m_page1.Save(); + m_page2.Save(); - m_page1.DoDataExchange(DDX_SAVE); - m_page2.DoDataExchange(DDX_SAVE); DoDataExchange(DDX_SAVE); - SetTabData(pTabData); m_tabSettings.Save(m_pOptionsRoot); @@ -199,49 +197,18 @@ LRESULT DlgSettingsTabs::OnListItemChanged(int /*idCtrl*/, LPNMHDR pnmh, BOOL& / if (pnmv->iItem < 0) return 0; - TabData* pTabData = reinterpret_cast(pnmv->lParam); - if (pnmv->uNewState & LVIS_SELECTED) { // selecting new item - m_page1.m_tabData = m_tabSettings.tabDataVector[m_listCtrl.GetSelectedIndex()]; - m_page2.m_tabData = m_tabSettings.tabDataVector[m_listCtrl.GetSelectedIndex()]; - - m_page1.m_strTitle = pTabData->strTitle.c_str(); - m_page1.m_strIcon = pTabData->strIcon.c_str(); - - m_page1.m_strShell = pTabData->strShell.c_str(); - m_page1.m_strInitialDir = pTabData->strInitialDir.c_str(); - - m_page2.m_nBkType = static_cast(pTabData->backgroundImageType); - m_page2.m_strBkImage = pTabData->imageData.strFilename.c_str(); - m_page2.m_nRelative = pTabData->imageData.bRelative ? 1 : 0; - m_page2.m_nExtend = pTabData->imageData.bExtend ? 1 : 0; - - m_page1.m_comboCursor.SetCurSel(pTabData->dwCursorStyle); - - m_page2.m_comboBkPosition.SetCurSel(static_cast(pTabData->imageData.imagePosition)); - - m_page2.m_sliderTintOpacity.SetPos(pTabData->imageData.byTintOpacity); - m_page2.UpdateSliderText(); - - m_page2.EnableControls(); - - m_page1.m_staticCursorColor.Invalidate(); - - m_page2.m_staticBkColor.Invalidate(); - m_page2.m_staticTintColor.Invalidate(); - - m_page1.DoDataExchange(DDX_LOAD); - m_page2.DoDataExchange(DDX_LOAD); + m_page1.Load(m_tabSettings.tabDataVector[m_listCtrl.GetSelectedIndex()]); + m_page2.Load(m_tabSettings.tabDataVector[m_listCtrl.GetSelectedIndex()]); } else if (pnmv->uOldState & LVIS_SELECTED) { // deselecting item - m_page1.DoDataExchange(DDX_SAVE); - m_page2.DoDataExchange(DDX_SAVE); - SetTabData(pTabData); - m_listCtrl.SetItemText(pnmv->iItem, 0, m_page1.m_strTitle); + m_page1.Save(); + m_page2.Save(); + m_listCtrl.SetItemText(pnmv->iItem, 0, m_page1.GetTabTitle()); } return 0; @@ -278,36 +245,6 @@ LRESULT DlgSettingsTabs::OnTabItemChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -void DlgSettingsTabs::SetTabData(TabData* pTabData) -{ - pTabData->strTitle = m_page1.m_strTitle; - pTabData->strIcon = m_page1.m_strIcon; - - pTabData->strShell = m_page1.m_strShell; - pTabData->strInitialDir = m_page1.m_strInitialDir; - - pTabData->backgroundImageType = static_cast(m_page2.m_nBkType); - - if (pTabData->backgroundImageType != bktypeNone) - { - pTabData->crBackgroundColor = RGB(0, 0, 0); - } - - pTabData->imageData.strFilename = m_page2.m_strBkImage; - pTabData->imageData.bRelative = m_page2.m_nRelative > 0; - pTabData->imageData.bExtend = m_page2.m_nExtend > 0; - - pTabData->dwCursorStyle = m_page1.m_comboCursor.GetCurSel(); - - pTabData->imageData.imagePosition = static_cast(m_page2.m_comboBkPosition.GetCurSel()); - pTabData->imageData.byTintOpacity = static_cast(m_page2.m_sliderTintOpacity.GetPos()); -} - -////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// void DlgSettingsTabs::MoveListItem(int nItem, int nDirection) diff --git a/Console/DlgSettingsTabs.h b/Console/DlgSettingsTabs.h index d97569b7..a4d1cee4 100644 --- a/Console/DlgSettingsTabs.h +++ b/Console/DlgSettingsTabs.h @@ -59,7 +59,6 @@ class DlgSettingsTabs private: - void SetTabData(TabData* pTabData); void MoveListItem(int nItem, int nDirection); private: diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 014a9db9..920c8a79 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -100,6 +100,9 @@ BOOL MainFrame::OnIdle() LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { + ControlsSettings& controlsSettings= g_settingsHandler->GetAppearanceSettings().controlsSettings; + PositionSettings& positionSettings= g_settingsHandler->GetAppearanceSettings().positionSettings; + // create command bar window HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE); // attach menu @@ -136,7 +139,7 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, #else CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE); #endif - AddSimpleReBarBand(hWndCmdBar, NULL, FALSE); + AddSimpleReBarBand(hWndCmdBar, NULL, FALSE); AddSimpleReBarBand(hWndToolBar, NULL, TRUE); #ifdef _USE_AERO @@ -150,10 +153,12 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, // initialize tabs UpdateTabsMenu(m_CmdBar.GetMenu(), m_tabsMenu); SetReflectNotifications(true); - DWORD dwTabWindowOtherStyles = CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_HOTTRACK; - if( g_settingsHandler->GetAppearanceSettings().controlsSettings.bTabsBottom ) - dwTabWindowOtherStyles |= CTCS_BOTTOM; - CreateTabWindow(m_hWnd, rcDefault, dwTabWindowOtherStyles); +// SetTabStyles(CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_BOLDSELECTEDTAB); + + DWORD dwTabStyles = CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_HOTTRACK; + if (controlsSettings.bTabsOnBottom) dwTabStyles |= CTCS_BOTTOM; + + CreateTabWindow(m_hWnd, rcDefault, dwTabStyles); // create initial console window(s) if (m_startupTabs.size() == 0) @@ -206,9 +211,6 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, SetWindowStyles(); - ControlsSettings& controlsSettings= g_settingsHandler->GetAppearanceSettings().controlsSettings; - PositionSettings& positionSettings= g_settingsHandler->GetAppearanceSettings().positionSettings; - ShowMenu(controlsSettings.bShowMenu ? TRUE : FALSE); ShowToolbar(controlsSettings.bShowToolbar ? TRUE : FALSE); ShowStatusbar(controlsSettings.bShowStatusbar ? TRUE : FALSE); @@ -340,7 +342,8 @@ LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, UnregisterGlobalHotkeys(); - bHandled = false; + DestroyWindow(); + PostQuitMessage(0); return 0; } @@ -1710,46 +1713,65 @@ void MainFrame::UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu) tabsMenu.InsertMenuItem(dwId-ID_NEW_TAB_1, TRUE, &subMenuItem); - // To draw icons with good transparency - CIcon tabSmallIcon; + // create menu icons with proper transparency (thanks to chrisz for the patch) + CIcon tabSmallIcon; + + if ((*it)->bUseDefaultIcon || ((*it)->strIcon.length() > 0)) + { + if ((*it)->menuBitmap.IsNull()) + { - // on essaye de charger l'icone - if( tabDataVector[dwId-ID_NEW_TAB_1]->strIcon.length() > 0 ) - { - tabSmallIcon.Attach( - static_cast( - ::LoadImage( - NULL, - Helpers::ExpandEnvironmentStrings(tabDataVector[dwId-ID_NEW_TAB_1]->strIcon).c_str(), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR|LR_LOADFROMFILE))); - } - else - { - tabSmallIcon.Attach( - static_cast( - ::LoadImage( - ::GetModuleHandle(NULL), - MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR))); - } + if ((*it)->strIcon.length() > 0) + { + tabSmallIcon.Attach( + static_cast( + ::LoadImage( + NULL, + Helpers::ExpandEnvironmentStrings((*it)->strIcon).c_str(), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR|LR_LOADFROMFILE + ) + ) + ); + } + else if ((*it)->bUseDefaultIcon) + { + tabSmallIcon.Attach( + static_cast( + ::LoadImage( + ::GetModuleHandle(NULL), + MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR + ) + ) + ); + } + + CDC dc; - CBitmap bmpCopy; - bmpCopy.CreateCompatibleBitmap(this->GetDC(),16,16); - CDC dc; - dc.CreateCompatibleDC(this->GetDC()); - dc.SelectBitmap(bmpCopy.m_hBitmap); - dc.FillSolidRect(0,0,16,16,::GetSysColor(COLOR_MENU)); - dc.DrawIconEx(0,0,tabSmallIcon.m_hIcon,16,16); + (*it)->menuBitmap.CreateCompatibleBitmap(::GetDC(NULL), 16, 16); - tabDataVector[dwId-ID_NEW_TAB_1]->hMenuBitmap = (HBITMAP) CopyImage(bmpCopy.m_hBitmap,IMAGE_BITMAP,(int)GetSystemMetrics(SM_CXMENUCHECK),(int)GetSystemMetrics(SM_CYMENUCHECK),0); + dc.CreateCompatibleDC(::GetDC(NULL)); + dc.SelectBitmap((*it)->menuBitmap); + dc.FillSolidRect(0, 0, 16, 16, ::GetSysColor(COLOR_MENU)); + dc.DrawIconEx(0, 0, tabSmallIcon.m_hIcon, 16, 16); + } + } + else + { + // destroy icon bitmap + if (!(*it)->menuBitmap.IsNull()) (*it)->menuBitmap.DeleteObject(); + } - tabsMenu.SetMenuItemBitmaps(dwId, MF_BYCOMMAND, tabDataVector[dwId-ID_NEW_TAB_1]->hMenuBitmap, tabDataVector[dwId-ID_NEW_TAB_1]->hMenuBitmap); + if (!(*it)->menuBitmap.IsNull()) + { + tabsMenu.SetMenuItemBitmaps(dwId, MF_BYCOMMAND, (*it)->menuBitmap, NULL); + } } // set tabs menu as popup submenu @@ -2187,7 +2209,7 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal m_dwWindowWidth = rectWindow.Width(); m_dwWindowHeight= rectWindow.Height(); - SetMargins(); + SetMargins(); } ////////////////////////////////////////////////////////////////////////////// @@ -2198,7 +2220,7 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal void MainFrame::SetMargins(void) { CReBarCtrl rebar(m_hWndToolBar); - DWORD dwStyle = this->m_TabCtrl.GetStyle(); + DWORD dwStyle = this->m_TabCtrl.GetStyle(); if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) { m_Margins.cyTopHeight = rebar.GetBarHeight(); @@ -2226,12 +2248,12 @@ void MainFrame::SetMargins(void) } void MainFrame::SetTransparency() - { +{ // set transparency - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; + StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; - // RAZ + // RAZ SetWindowLong( GWL_EXSTYLE, GetWindowLong(GWL_EXSTYLE) & ~WS_EX_LAYERED); @@ -2411,13 +2433,13 @@ void MainFrame::CreateStatusBar() { m_hWndStatusBar = m_statusBar.Create(*this); #ifdef _USE_AERO - aero::Subclass(m_ASB, m_hWndStatusBar); + aero::Subclass(m_ASB, m_hWndStatusBar); #endif - UIAddStatusBar(m_hWndStatusBar); + UIAddStatusBar(m_hWndStatusBar); int arrPanes[] = { ID_DEFAULT_PANE, IDPANE_ROWS_COLUMNS }; - - m_statusBar.SetPanes(arrPanes, sizeof(arrPanes)/sizeof(int), false); + + m_statusBar.SetPanes(arrPanes, sizeof(arrPanes)/sizeof(int), false); m_statusBar.SetPaneWidth(IDPANE_ROWS_COLUMNS, 50); } diff --git a/Console/PageSettingsTabs1.cpp b/Console/PageSettingsTabs1.cpp index b15ead64..3ca88296 100644 --- a/Console/PageSettingsTabs1.cpp +++ b/Console/PageSettingsTabs1.cpp @@ -18,6 +18,7 @@ PageSettingsTabs1::PageSettingsTabs1() : m_tabData() , m_strTitle(L"") , m_strIcon(L"") +, m_nUseDefaultIcon(0) , m_strShell(L"") , m_strInitialDir(L"") { @@ -187,3 +188,74 @@ LRESULT PageSettingsTabs1::OnClickedBtnBrowseDir(WORD /*wNotifyCode*/, WORD /*wI ////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// + +LRESULT PageSettingsTabs1::OnCheckDefaultIcon(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + DoDataExchange(DDX_SAVE); + EnableControls(); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void PageSettingsTabs1::EnableControls() +{ + BOOL bEnableEditIconCtrls = TRUE; + + if (m_nUseDefaultIcon > 0) bEnableEditIconCtrls = FALSE; + + GetDlgItem(IDC_TAB_ICON).EnableWindow(bEnableEditIconCtrls); + GetDlgItem(IDC_BTN_BROWSE_ICON).EnableWindow(bEnableEditIconCtrls); +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void PageSettingsTabs1::Load(shared_ptr& tabData) +{ + m_tabData = tabData; + + m_strTitle = m_tabData->strTitle.c_str(); + m_strIcon = m_tabData->strIcon.c_str(); + m_nUseDefaultIcon = m_tabData->bUseDefaultIcon ? 1 : 0; + + m_strShell = m_tabData->strShell.c_str(); + m_strInitialDir = m_tabData->strInitialDir.c_str(); + + m_comboCursor.SetCurSel(m_tabData->dwCursorStyle); + + m_staticCursorColor.Invalidate(); + + DoDataExchange(DDX_LOAD); + + EnableControls(); +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void PageSettingsTabs1::Save() +{ + DoDataExchange(DDX_SAVE); + + m_tabData->strTitle = m_strTitle; + m_tabData->strIcon = m_strIcon; + m_tabData->bUseDefaultIcon = (m_nUseDefaultIcon > 0); + + m_tabData->strShell = m_strShell; + m_tabData->strInitialDir = m_strInitialDir; + + m_tabData->dwCursorStyle = m_comboCursor.GetCurSel(); +} + +////////////////////////////////////////////////////////////////////////////// diff --git a/Console/PageSettingsTabs1.h b/Console/PageSettingsTabs1.h index 8345d020..44c7a89f 100644 --- a/Console/PageSettingsTabs1.h +++ b/Console/PageSettingsTabs1.h @@ -25,6 +25,7 @@ class PageSettingsTabs1 BEGIN_DDX_MAP(PageSettingsTabs1) DDX_TEXT(IDC_TAB_TITLE, m_strTitle) DDX_TEXT(IDC_TAB_ICON, m_strIcon) + DDX_CHECK(IDC_CHECK_DEFAULT_ICON, m_nUseDefaultIcon) DDX_TEXT(IDC_TAB_SHELL, m_strShell) DDX_TEXT(IDC_TAB_INIT_DIR, m_strInitialDir) END_DDX_MAP() @@ -37,6 +38,7 @@ class PageSettingsTabs1 COMMAND_HANDLER(IDC_TAB_TITLE, EN_CHANGE, OnTabTitleChange) COMMAND_HANDLER(IDC_CURSOR_COLOR, BN_CLICKED, OnClickedCursorColor) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_ICON, OnBtnBrowseIcon) + COMMAND_ID_HANDLER(IDC_CHECK_DEFAULT_ICON, OnCheckDefaultIcon) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_SHELL, OnClickedBtnBrowseShell) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_DIR, OnClickedBtnBrowseDir) END_MSG_MAP() @@ -55,8 +57,16 @@ class PageSettingsTabs1 LRESULT OnBtnBrowseIcon(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnClickedBtnBrowseShell(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnClickedBtnBrowseDir(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnCheckDefaultIcon(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); - public: + void EnableControls(); + + void Load(shared_ptr& tabData); + void Save(); + + const CString& GetTabTitle() const { return m_strTitle; } + + private: shared_ptr m_tabData; @@ -65,6 +75,7 @@ class PageSettingsTabs1 CString m_strTitle; CString m_strIcon; + int m_nUseDefaultIcon; CString m_strShell; CString m_strInitialDir; diff --git a/Console/PageSettingsTabs2.cpp b/Console/PageSettingsTabs2.cpp index 87032b69..992d726e 100644 --- a/Console/PageSettingsTabs2.cpp +++ b/Console/PageSettingsTabs2.cpp @@ -249,3 +249,40 @@ void PageSettingsTabs2::EnableControls() } ////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void PageSettingsTabs2::Load(shared_ptr& tabData) +{ + m_tabData = tabData; + + m_nBkType = static_cast(m_tabData->backgroundImageType); + m_strBkImage = m_tabData->imageData.strFilename.c_str(); + m_nRelative = m_tabData->imageData.bRelative ? 1 : 0; + m_nExtend = m_tabData->imageData.bExtend ? 1 : 0; + + m_comboBkPosition.SetCurSel(static_cast(m_tabData->imageData.imagePosition)); + + m_sliderTintOpacity.SetPos(m_tabData->imageData.byTintOpacity); + UpdateSliderText(); + + m_staticBkColor.Invalidate(); + m_staticTintColor.Invalidate(); + + DoDataExchange(DDX_LOAD); + + EnableControls(); +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +void PageSettingsTabs2::Save() +{ + DoDataExchange(DDX_SAVE); +} + +////////////////////////////////////////////////////////////////////////////// diff --git a/Console/PageSettingsTabs2.h b/Console/PageSettingsTabs2.h index 10ca816f..c469df1a 100644 --- a/Console/PageSettingsTabs2.h +++ b/Console/PageSettingsTabs2.h @@ -59,7 +59,10 @@ class PageSettingsTabs2 void UpdateSliderText(); void EnableControls(); - public: + void Load(shared_ptr& tabData); + void Save(); + + private: shared_ptr m_tabData; diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index deb9ff31..65c165b6 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -366,7 +366,7 @@ ControlsSettings::ControlsSettings() , bShowStatusbar(true) , bShowTabs(true) , bHideSingleTab(false) -, bTabsBottom(false) +, bTabsOnBottom(false) , bShowScrollbars(true) , bFlatScrollbars(false) { @@ -388,7 +388,7 @@ bool ControlsSettings::Load(const CComPtr& pSettingsRoot) XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"show_statusbar"), bShowStatusbar, true); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"show_tabs"), bShowTabs, true); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"hide_single_tab"), bHideSingleTab, false); - XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"tabs_bottom"), bTabsBottom, false); + XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"tabs_on_bottom"), bTabsOnBottom, false); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"show_scrollbars"), bShowScrollbars, true); XmlHelper::GetAttribute(pCtrlsElement, CComBSTR(L"flat_scrollbars"), bFlatScrollbars, false); @@ -411,7 +411,7 @@ bool ControlsSettings::Save(const CComPtr& pSettingsRoot) XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"show_statusbar"), bShowStatusbar); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"show_tabs"), bShowTabs); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"hide_single_tab"), bHideSingleTab); - XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"tabs_bottom"), bTabsBottom); + XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"tabs_on_bottom"), bTabsOnBottom); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"show_scrollbars"), bShowScrollbars); XmlHelper::SetAttribute(pCtrlsElement, CComBSTR(L"flat_scrollbars"), bFlatScrollbars); @@ -430,7 +430,7 @@ ControlsSettings& ControlsSettings::operator=(const ControlsSettings& other) bShowStatusbar = other.bShowStatusbar; bShowTabs = other.bShowTabs; bHideSingleTab = other.bHideSingleTab; - bTabsBottom = other.bTabsBottom; + bTabsOnBottom = other.bTabsOnBottom; bShowScrollbars = other.bShowScrollbars; bFlatScrollbars = other.bFlatScrollbars; @@ -1496,6 +1496,7 @@ bool TabSettings::Load(const CComPtr& pSettingsRoot) XmlHelper::GetAttribute(pTabElement, CComBSTR(L"title"), tabData->strTitle, L"Console"); XmlHelper::GetAttribute(pTabElement, CComBSTR(L"icon"), tabData->strIcon, L""); + XmlHelper::GetAttribute(pTabElement, CComBSTR(L"use_default_icon"), tabData->bUseDefaultIcon, false); tabDataVector.push_back(tabData); @@ -1607,6 +1608,8 @@ bool TabSettings::Save(const CComPtr& pSettingsRoot) XmlHelper::SetAttribute(pNewTabElement, CComBSTR(L"icon"), (*itTab)->strIcon); } + XmlHelper::SetAttribute(pNewTabElement, CComBSTR(L"use_default_icon"), (*itTab)->bUseDefaultIcon); + // add tag CComPtr pNewConsoleElement; CComPtr pNewConsoleOut; diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index d8cfd1df..4db72077 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -136,7 +136,7 @@ struct ControlsSettings bool bShowStatusbar; bool bShowTabs; bool bHideSingleTab; - bool bTabsBottom; + bool bTabsOnBottom; bool bShowScrollbars; bool bFlatScrollbars; }; @@ -223,7 +223,7 @@ enum TransparencyType transNone = 0, transAlpha = 1, transColorKey = 2, - transGlass = 3 + transGlass = 3 }; ////////////////////////////////////////////////////////////////////////////// @@ -580,25 +580,22 @@ struct TabData TabData(const wstring& shell, const wstring& initialDir) : strTitle(L"Console") , strIcon(L"") + , bUseDefaultIcon(false) , strShell(shell) , strInitialDir(initialDir) , dwCursorStyle(0) , crCursorColor(RGB(255, 255, 255)) , backgroundImageType(bktypeNone) , crBackgroundColor(RGB(0, 0, 0)) + , menuBitmap() , imageData() - , hMenuBitmap(NULL) { } - ~TabData() - { - ::DeleteObject(hMenuBitmap); - } - // custom shell settings wstring strTitle; wstring strIcon; + bool bUseDefaultIcon; wstring strShell; wstring strInitialDir; @@ -609,9 +606,9 @@ struct TabData BackgroundImageType backgroundImageType; COLORREF crBackgroundColor; - ImageData imageData; + CBitmap menuBitmap; - HBITMAP hMenuBitmap; + ImageData imageData; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/console.xml b/Console/console.xml index 3bf1babb..9d1bd0df 100644 --- a/Console/console.xml +++ b/Console/console.xml @@ -25,7 +25,7 @@ - + diff --git a/Console/resource.h b/Console/resource.h index 7a08895a..7f22ffc0 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -123,10 +123,8 @@ #define IDC_CHECK_HIDE_SCROLLBARS 1094 #define IDC_CHECK_SHOW_SCROLLBARS 1094 #define IDC_RADIO_DOCK_NONE 1095 -#define IDC_CHECK_SHOW_SCROLLBARS2 1095 #define IDC_CHECK_FLAT_SCROLLBARS 1095 #define IDC_RADIO_DOCK_TL 1096 -#define IDC_CHECK_TABS_BOTTOM 1096 #define IDC_RADIO_DOCK_TR 1097 #define IDC_RADIO_DOCK_BL 1098 #define IDC_RADIO_DOCK_BR 1099 @@ -214,10 +212,11 @@ #define IDC_COMBO_SMOOTHING 1169 #define IDC_CHECK_LEAVE_HIGHLIGHTED 1170 #define IDC_CHECK_START_HIDDEN 1171 -#define IDC_RADIO1 1172 -#define IDC_APPTEXT 1173 -#define IDC_APPICON 1174 -#define ID_RENAME_TAB_OK 1175 +#define IDC_CHECK_DEFAULT_ICON 1172 +#define IDC_CHECK_TABS_ON_BOTTOM 1173 +#define IDC_APPTEXT 1174 +#define IDC_APPICON 1175 +#define ID_RENAME_TAB_OK 1176 #define ID_NEW_TAB_1 2000 #define ID_SWITCH_TAB_1 2100 #define ID_NEXT_TAB 2200 @@ -243,7 +242,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 222 #define _APS_NEXT_COMMAND_VALUE 32794 -#define _APS_NEXT_CONTROL_VALUE 1176 +#define _APS_NEXT_CONTROL_VALUE 1177 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index 57141885..99ba3177 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -22,7 +22,7 @@ ConsoleHandler::ConsoleHandler() , m_cursorInfo() , m_consoleBuffer() , m_consoleCopyInfo() -, m_consolePasteInfo() +, m_consoleTextInfo() , m_consoleMouseEvent() , m_newConsoleSize() , m_newScrollPos() @@ -104,8 +104,8 @@ bool ConsoleHandler::OpenSharedObjects() // copy info m_consoleCopyInfo.Open((SharedMemNames::formatCopyInfo % dwProcessId).str(), syncObjBoth); - // paste info (used for pasting and sending text to console) - m_consolePasteInfo.Open((SharedMemNames::formatPasteInfo % dwProcessId).str(), syncObjBoth); + // text info (used for sending text to console) + m_consoleTextInfo.Open((SharedMemNames::formatTextInfo % dwProcessId).str(), syncObjBoth); // mouse event m_consoleMouseEvent.Open((SharedMemNames::formatMouseEvent % dwProcessId).str(), syncObjBoth); @@ -128,22 +128,20 @@ void ConsoleHandler::ReadConsoleBuffer() { // we take a fresh STDOUT handle - seems to work better (in case a program // has opened a new screen output buffer) - shared_ptr hStdOut( - ::CreateFile( + // no need to call CloseHandle when done, we're reusing console handles + HANDLE hStdOut = ::CreateFile( L"CONOUT$", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, - 0), - ::CloseHandle); + 0); - // get total console size CONSOLE_SCREEN_BUFFER_INFO csbiConsole; COORD coordConsoleSize; - ::GetConsoleScreenBufferInfo(hStdOut.get(), &csbiConsole); + ::GetConsoleScreenBufferInfo(hStdOut, &csbiConsole); coordConsoleSize.X = csbiConsole.srWindow.Right - csbiConsole.srWindow.Left + 1; coordConsoleSize.Y = csbiConsole.srWindow.Bottom - csbiConsole.srWindow.Top + 1; @@ -190,7 +188,7 @@ void ConsoleHandler::ReadConsoleBuffer() // TRACE(L"Reading region: (%i, %i) - (%i, %i)\n", srBuffer.Left, srBuffer.Top, srBuffer.Right, srBuffer.Bottom); ::ReadConsoleOutput( - hStdOut.get(), + hStdOut, pScreenBuffer.get() + dwScreenBufferOffset, coordBufferSize, coordStart, @@ -214,7 +212,7 @@ void ConsoleHandler::ReadConsoleBuffer() */ ::ReadConsoleOutput( - hStdOut.get(), + hStdOut, pScreenBuffer.get() + dwScreenBufferOffset, coordBufferSize, coordStart, @@ -234,7 +232,7 @@ void ConsoleHandler::ReadConsoleBuffer() m_dwScreenBufferSize = dwScreenBufferSize; ::CopyMemory(m_consoleBuffer.Get(), pScreenBuffer.get(), m_dwScreenBufferSize*sizeof(CHAR_INFO)); ::CopyMemory(m_consoleInfo.Get(), &csbiConsole, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); - ::GetConsoleCursorInfo(hStdOut.get(), m_cursorInfo.Get()); + ::GetConsoleCursorInfo(hStdOut, m_cursorInfo.Get()); m_consoleBuffer.SetReqEvent(); } @@ -583,110 +581,14 @@ void ConsoleHandler::CopyConsoleText() ////////////////////////////////////////////////////////////////////////////// -void ConsoleHandler::PasteConsoleText(HANDLE hStdIn, const shared_ptr& pszPasteBuffer) +void ConsoleHandler::SendConsoleText(HANDLE hStdIn, const shared_ptr& textBuffer) { - wchar_t* pszText = NULL; - HANDLE hData = NULL; - - if (pszPasteBuffer.get() == NULL) - { - // pasting text - if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) return; - - if (!::OpenClipboard(m_consoleParams->hwndConsoleWindow)) return; - - hData = ::GetClipboardData(CF_UNICODETEXT); - pszText = reinterpret_cast(::GlobalLock(hData)); - } - else - { - // text sent to console - pszText = pszPasteBuffer.get(); - } - - - - -/* - size_t textLen = wcslen(pszText); - size_t textOffset = 0; - - size_t maxConsoleInputCount = 512; - size_t consoleInputCount = 0; - - scoped_array consoleInputs(new INPUT_RECORD[maxConsoleInputCount]); - ::ZeroMemory(consoleInputs.get(), sizeof(INPUT_RECORD)*maxConsoleInputCount); - - for (; textOffset < textLen; ++textOffset) - { - if (consoleInputCount == maxConsoleInputCount) - { - WriteConsoleInput(hStdIn, consoleInputs, consoleInputCount, maxConsoleInputCount); - } - - if ((pszText[textOffset] == L'\r') || (pszText[textOffset] == L'\n')) - { - if (consoleInputCount > 0) - { - WriteConsoleInput(hStdIn, consoleInputs, consoleInputCount, maxConsoleInputCount); - } - - short sInputCount = 0; - - // first, we need to reset SHIFT/CTRL/ALT keys - scoped_array kbdInputs(new INPUT[5]); - ::ZeroMemory(kbdInputs.get(), 5*sizeof(INPUT)); - - SetResetKeyInput(kbdInputs, VK_SHIFT, sInputCount); - SetResetKeyInput(kbdInputs, VK_CONTROL, sInputCount); - SetResetKeyInput(kbdInputs, VK_MENU, sInputCount); - - kbdInputs[sInputCount].type = INPUT_KEYBOARD; - kbdInputs[sInputCount].ki.wVk = VK_RETURN; - kbdInputs[sInputCount].ki.dwFlags = 0; + wchar_t* pszText = textBuffer.get(); + size_t textLen = wcslen(pszText); + size_t partLen = 512; + size_t parts = textLen/partLen; + size_t offset = 0; - ++sInputCount; - - kbdInputs[sInputCount].type = INPUT_KEYBOARD; - kbdInputs[sInputCount].ki.wVk = VK_RETURN; - kbdInputs[sInputCount].ki.dwFlags = KEYEVENTF_KEYUP; - - ++sInputCount; - - ::SendInput(sInputCount, kbdInputs.get(), sizeof(INPUT)); - ::Sleep(10); - - if ((pszText[textOffset] == L'\r') && (pszText[textOffset+1] == L'\n')) ++textOffset; - } - else - { - consoleInputs[consoleInputCount].EventType = KEY_EVENT; - consoleInputs[consoleInputCount].Event.KeyEvent.bKeyDown = TRUE; - consoleInputs[consoleInputCount].Event.KeyEvent.wRepeatCount = 1; - consoleInputs[consoleInputCount].Event.KeyEvent.wVirtualKeyCode = LOBYTE(::VkKeyScan(pszText[textOffset])); - consoleInputs[consoleInputCount].Event.KeyEvent.wVirtualScanCode = 0; - consoleInputs[consoleInputCount].Event.KeyEvent.uChar.UnicodeChar = pszText[textOffset]; - consoleInputs[consoleInputCount].Event.KeyEvent.dwControlKeyState = 0; - - ++consoleInputCount; - } - } - - if (consoleInputCount > 0) - { - WriteConsoleInput(hStdIn, consoleInputs, consoleInputCount, 0); - } - -*/ - - - - size_t textLen = wcslen(pszText); - size_t partLen = 512; - size_t parts = textLen/partLen; - size_t offset = 0; - -// TRACE(L"Pasting %i\n", textLen); for (size_t part = 0; part < parts+1; ++part) { size_t keyEventCount = 0; @@ -704,16 +606,6 @@ void ConsoleHandler::PasteConsoleText(HANDLE hStdIn, const shared_ptr& { if ((pszText[offset] == L'\r') || (pszText[offset] == L'\n')) { -/* - pKeyEvents[i].EventType = KEY_EVENT; - pKeyEvents[i].Event.KeyEvent.bKeyDown = TRUE; - pKeyEvents[i].Event.KeyEvent.wRepeatCount = 1; - pKeyEvents[i].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; - pKeyEvents[i].Event.KeyEvent.wVirtualScanCode = 0; - pKeyEvents[i].Event.KeyEvent.uChar.UnicodeChar = L'\n'; - pKeyEvents[i].Event.KeyEvent.dwControlKeyState = 0; -*/ - if ((pszText[offset] == L'\r') && (pszText[offset+1] == L'\n')) ++offset; if (keyEventCount > 0) @@ -747,28 +639,6 @@ void ConsoleHandler::PasteConsoleText(HANDLE hStdIn, const shared_ptr& ::WriteConsoleInput(hStdIn, pKeyEvents.get(), static_cast(keyEventCount), &dwTextWritten); } } - - - if (pszPasteBuffer.get() == NULL) - { - ::GlobalUnlock(hData); - ::CloseClipboard(); - } - -// TRACE(L"\n"); - - -// for (DWORD i = 100; i < 1000; ++i) -// { -// INPUT_RECORD in; -// ::ZeroMemory(&in, sizeof(INPUT_RECORD)); -// -// in.EventType = MENU_EVENT; -// in.Event.MenuEvent.dwCommandId = i; -// -// DWORD dwTextWritten = 0; -// ::WriteConsoleInput(hStdIn, &in, 1, &dwTextWritten); -// } } ////////////////////////////////////////////////////////////////////////////// @@ -790,32 +660,6 @@ void ConsoleHandler::SetResetKeyInput(scoped_array& kbdInputs, WORD wVk, ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -void ConsoleHandler::WriteConsoleInput(HANDLE hStdIn, scoped_array& consoleInputs, size_t& consoleInputCount, size_t maxConsoleInputCount) -{ - if (consoleInputCount > 0) - { - DWORD dwTextWritten = 0; - ::WriteConsoleInput(hStdIn, consoleInputs.get(), static_cast(consoleInputCount), &dwTextWritten); - } - - if (maxConsoleInputCount > 0) - { - consoleInputs.reset(new INPUT_RECORD[maxConsoleInputCount]); - ::ZeroMemory(consoleInputs.get(), sizeof(INPUT_RECORD)*maxConsoleInputCount); - } - else - { - consoleInputs.reset(); - } - - consoleInputCount = 0; -} - -////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// void ConsoleHandler::SendMouseEvent(HANDLE hStdIn) @@ -931,41 +775,29 @@ DWORD ConsoleHandler::MonitorThread() TRACE(L"Parent process handle: 0x%08X\n", m_hParentProcess.get()); -/* - HANDLE hStdOut = ::GetStdHandle(STD_OUTPUT_HANDLE); - HANDLE hStdIn = ::GetStdHandle(STD_INPUT_HANDLE); -*/ - - - shared_ptr hStdOut( - ::CreateFile( - L"CONOUT$", - GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - 0, - 0), - ::CloseHandle); - - shared_ptr hStdIn( - ::CreateFile( - L"CONIN$", - GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - 0, - 0), - ::CloseHandle); - -// HANDLE hStdErr = ::GetStdHandle(STD_ERROR_HANDLE); - - SetConsoleParams(::GetCurrentThreadId(), hStdOut.get()); + HANDLE hStdOut = ::CreateFile( + L"CONOUT$", + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + 0); + + HANDLE hStdIn = ::CreateFile( + L"CONIN$", + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + 0); + + SetConsoleParams(::GetCurrentThreadId(), hStdOut); ::SuspendThread(GetCurrentThread()); - ResizeConsoleWindow(hStdOut.get(), m_consoleParams->dwColumns, m_consoleParams->dwRows, 0); + ResizeConsoleWindow(hStdOut, m_consoleParams->dwColumns, m_consoleParams->dwRows, 0); // FIX: this seems to case problems on startup // ReadConsoleBuffer(); @@ -973,13 +805,12 @@ DWORD ConsoleHandler::MonitorThread() HANDLE arrWaitHandles[] = { m_hMonitorThreadExit.get(), -// hStdErr, m_consoleCopyInfo.GetReqEvent(), - m_consolePasteInfo.GetReqEvent(), + m_consoleTextInfo.GetReqEvent(), m_newScrollPos.GetReqEvent(), m_consoleMouseEvent.GetReqEvent(), m_newConsoleSize.GetReqEvent(), - hStdOut.get(), + hStdOut, m_hParentProcess.get() }; @@ -991,44 +822,6 @@ DWORD ConsoleHandler::MonitorThread() FALSE, m_consoleParams->dwRefreshInterval)) != WAIT_OBJECT_0) { -/* - if (dwWaitRes == WAIT_FAILED) - { - TRACE(L"dwWaitRes: %i\n", dwWaitRes); - - if (::WaitForSingleObject(m_hMonitorThreadExit.get(), 0) == WAIT_FAILED) - { - TRACE(L"m_hMonitorThreadExit.get()\n"); - } - - if (::WaitForSingleObject(hStdOut.get(), 0) == WAIT_FAILED) - { - TRACE(L"hStdOut.get()\n"); - } - - if (::WaitForSingleObject(hStdErr, 0) == WAIT_FAILED) - { - TRACE(L"hStdErr\n"); - } - - if (::WaitForSingleObject(m_consolePaste.GetEvent(), 0) == WAIT_FAILED) - { - TRACE(L"m_consolePaste.GetEvent()\n"); - } - - if (::WaitForSingleObject(m_newConsoleSize.GetEvent(), 0) == WAIT_FAILED) - { - TRACE(L"m_newConsoleSize.GetEvent()\n"); - } - - if (::WaitForSingleObject(m_newScrollPos.GetEvent(), 0) == WAIT_FAILED) - { - TRACE(L"m_newScrollPos.GetEvent()\n"); - } - - } -*/ - switch (dwWaitRes) { // copy request @@ -1041,22 +834,22 @@ DWORD ConsoleHandler::MonitorThread() break; } - // paste request + // send text request case WAIT_OBJECT_0 + 2 : { - SharedMemoryLock memLock(m_consolePasteInfo); + SharedMemoryLock memLock(m_consoleTextInfo); - shared_ptr pszPasteBuffer; + shared_ptr textBuffer; - if (*m_consolePasteInfo.Get() != NULL) + if (*m_consoleTextInfo.Get() != NULL) { - pszPasteBuffer.reset( - reinterpret_cast(*m_consolePasteInfo.Get()), + textBuffer.reset( + reinterpret_cast(*m_consoleTextInfo.Get()), bind(::VirtualFreeEx, ::GetCurrentProcess(), _1, NULL, MEM_RELEASE)); } - PasteConsoleText(hStdIn.get(), pszPasteBuffer); - m_consolePasteInfo.SetRespEvent(); + SendConsoleText(hStdIn, textBuffer); + m_consoleTextInfo.SetRespEvent(); break; } @@ -1065,7 +858,7 @@ DWORD ConsoleHandler::MonitorThread() { SharedMemoryLock memLock(m_newScrollPos); - ScrollConsole(hStdOut.get(), m_newScrollPos->cx, m_newScrollPos->cy); + ScrollConsole(hStdOut, m_newScrollPos->cx, m_newScrollPos->cy); ReadConsoleBuffer(); break; } @@ -1075,7 +868,7 @@ DWORD ConsoleHandler::MonitorThread() { SharedMemoryLock memLock(m_consoleMouseEvent); - SendMouseEvent(hStdIn.get()); + SendMouseEvent(hStdIn); m_consoleMouseEvent.SetRespEvent(); break; } @@ -1085,13 +878,12 @@ DWORD ConsoleHandler::MonitorThread() { SharedMemoryLock memLock(m_newConsoleSize); - ResizeConsoleWindow(hStdOut.get(), m_newConsoleSize->dwColumns, m_newConsoleSize->dwRows, m_newConsoleSize->dwResizeWindowEdge); + ResizeConsoleWindow(hStdOut, m_newConsoleSize->dwColumns, m_newConsoleSize->dwRows, m_newConsoleSize->dwResizeWindowEdge); ReadConsoleBuffer(); break; } case WAIT_OBJECT_0 + 6 : -// case WAIT_OBJECT_0 + 2 : // something changed in the console // this has to be the last event, since it's the most // frequent one diff --git a/ConsoleHook/ConsoleHandler.h b/ConsoleHook/ConsoleHandler.h index 5493a713..2e0ea330 100644 --- a/ConsoleHook/ConsoleHandler.h +++ b/ConsoleHook/ConsoleHandler.h @@ -31,12 +31,10 @@ class ConsoleHandler void CopyConsoleText(); - void PasteConsoleText(HANDLE hStdIn, const shared_ptr& pszPasteBuffer); + void SendConsoleText(HANDLE hStdIn, const shared_ptr& textBuffer); void SetResetKeyInput(scoped_array& kbdInputs, WORD wVk, short& sCount); - void WriteConsoleInput(HANDLE hStdIn, scoped_array& consoleInputs, size_t& consoleInputCount, size_t maxConsoleInputCount); - void SendMouseEvent(HANDLE hStdIn); void ScrollConsole(HANDLE hStdOut, int nXDelta, int nYDelta); @@ -57,7 +55,7 @@ class ConsoleHandler SharedMemory m_cursorInfo; SharedMemory m_consoleBuffer; SharedMemory m_consoleCopyInfo; - SharedMemory m_consolePasteInfo; + SharedMemory m_consoleTextInfo; SharedMemory m_consoleMouseEvent; SharedMemory m_newConsoleSize; diff --git a/shared/SharedMemNames.h b/shared/SharedMemNames.h index bc3bf505..5d346eea 100644 --- a/shared/SharedMemNames.h +++ b/shared/SharedMemNames.h @@ -11,7 +11,7 @@ class SharedMemNames static wformat formatCursorInfo; static wformat formatBuffer; static wformat formatCopyInfo; - static wformat formatPasteInfo; + static wformat formatTextInfo; static wformat formatMouseEvent; static wformat formatNewConsoleSize; static wformat formatNewScrollPos; @@ -33,8 +33,8 @@ wformat SharedMemNames::formatInfo(L"Console2_consoleInfo_%1%"); wformat SharedMemNames::formatCursorInfo(L"Console2_cursorInfo_%1%"); wformat SharedMemNames::formatBuffer(L"Console2_consoleBuffer_%1%"); wformat SharedMemNames::formatCopyInfo(L"Console2_consoleCopyInfo_%1%"); -wformat SharedMemNames::formatPasteInfo(L"Console2_consolePasteInfo_%1%"); -wformat SharedMemNames::formatMouseEvent(L"Console2_formatMouseEvent_%1%"); +wformat SharedMemNames::formatTextInfo(L"Console2_consoleTextInfo_%1%"); +wformat SharedMemNames::formatMouseEvent(L"Console2_consoleMouseEvent_%1%"); wformat SharedMemNames::formatNewConsoleSize(L"Console2_newConsoleSize_%1%"); wformat SharedMemNames::formatNewScrollPos(L"Console2_newScrollPos_%1%"); From a6e7caf72b928e7f94b1251b66a6380cd0c21148 Mon Sep 17 00:00:00 2001 From: cbucher Date: Fri, 27 Aug 2010 18:42:37 +0200 Subject: [PATCH 006/207] show selection size in status bar --- Console/ConsoleView.cpp | 17 ++++++++--------- Console/MainFrame.cpp | 13 +++++++++++-- Console/MainFrame.h | 5 ++--- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index b0cf632a..30b1227d 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -527,11 +527,13 @@ LRESULT ConsoleView::OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL if (m_selectionHandler->GetState() == SelectionHandler::selstateStartedSelecting) { m_selectionHandler->EndSelection(); + m_mainFrame.SetSelectionSize(0); m_selectionHandler->ClearSelection(); } else if (m_selectionHandler->GetState() == SelectionHandler::selstateSelecting) { m_selectionHandler->EndSelection(); + m_mainFrame.SetSelectionSize(0); // copy on select if (g_settingsHandler->GetBehaviorSettings().copyPasteSettings.bCopyOnSelect) @@ -612,15 +614,12 @@ LRESULT ConsoleView::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& { MutexLock bufferLock(m_bufferMutex); m_selectionHandler->UpdateSelection(GetConsoleCoord(point), m_screenBuffer); - COORD coordStart; - COORD coordEnd; - m_selectionHandler->GetSelectionCoordinates(coordStart, coordEnd); - int iSelextedSize = (coordEnd.Y - coordStart.Y) * m_consoleHandler.GetConsoleParams()->dwColumns + - (coordEnd.X - coordStart.X) + 1; - TCHAR szBuff[128]; - _sntprintf(szBuff, sizeof(szBuff), _T("[%i]"), iSelextedSize); - m_mainFrame.UISetText(1, szBuff); - m_mainFrame.UIUpdateStatusBar(); + COORD coordStart; + COORD coordEnd; + m_selectionHandler->GetSelectionCoordinates(coordStart, coordEnd); + int iSelectionSize = (coordEnd.Y - coordStart.Y) * m_consoleHandler.GetConsoleParams()->dwColumns + + (coordEnd.X - coordStart.X) + 1; + m_mainFrame.SetSelectionSize(iSelectionSize); } BitBltOffscreen(); diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 920c8a79..90cb3a19 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -53,6 +53,7 @@ MainFrame::MainFrame , m_bRestoringWindow(false) , m_rectRestoredWnd(0, 0, 0, 0) , m_animationWindow() +, m_iSelectionSize(0) { m_Margins.cxLeftWidth = 0; m_Margins.cxRightWidth = 0; @@ -1794,13 +1795,21 @@ void MainFrame::UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu) void MainFrame::UpdateStatusBar() { CString strRowsCols; - - strRowsCols.Format(IDPANE_ROWS_COLUMNS, m_dwRows, m_dwColumns); + if( m_iSelectionSize ) + strRowsCols.Format(_T("[%i]"), m_iSelectionSize); + else + strRowsCols.Format(IDPANE_ROWS_COLUMNS, m_dwRows, m_dwColumns); UISetText(1, strRowsCols); UIUpdateStatusBar(); } +void MainFrame::SetSelectionSize(int iSelectionSize) +{ + m_iSelectionSize = iSelectionSize; + UpdateStatusBar(); +} + ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 550f5ca2..793d99f3 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -187,10 +187,8 @@ class MainFrame public: -// shared_ptr GetActiveView(); - void AdjustWindowRect(CRect& rect); -// void AdjustAndResizeConsoleView(CRect& rectView); + void SetSelectionSize(int iSelectionSize); private: @@ -256,6 +254,7 @@ class MainFrame DWORD m_dwRows; DWORD m_dwColumns; + int m_iSelectionSize; DWORD m_dwWindowWidth; DWORD m_dwWindowHeight; From a0cc54d4d09505aab733265c830838fdecbabd55 Mon Sep 17 00:00:00 2001 From: cbucher Date: Fri, 27 Aug 2010 18:47:25 +0200 Subject: [PATCH 007/207] disable flat scrollbar check box if "show scrollbar" is not checked --- Console/DlgSettingsStyles.cpp | 19 +++++++++++++++++++ Console/DlgSettingsStyles.h | 3 +++ 2 files changed, 22 insertions(+) diff --git a/Console/DlgSettingsStyles.cpp b/Console/DlgSettingsStyles.cpp index a5c70a09..c7e28c54 100644 --- a/Console/DlgSettingsStyles.cpp +++ b/Console/DlgSettingsStyles.cpp @@ -73,6 +73,7 @@ LRESULT DlgSettingsStyles::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM UpdateSliderText(m_sliderInactiveAlpha.m_hWnd); EnableTabControls(); + EnableScrollbarControls(); EnableTransparencyControls(); DoDataExchange(DDX_LOAD); @@ -183,6 +184,13 @@ LRESULT DlgSettingsStyles::OnClickedShowTabs(WORD /*wNotifyCode*/, WORD /*wID*/, return 0; } +LRESULT DlgSettingsStyles::OnClickedShowScrollbars(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + DoDataExchange(DDX_SAVE); + EnableScrollbarControls(); + return 0; +} + ////////////////////////////////////////////////////////////////////////////// @@ -280,6 +288,7 @@ void DlgSettingsStyles::UpdateSliderText(HWND hwndSlider) void DlgSettingsStyles::EnableTabControls() { GetDlgItem(IDC_CHECK_HIDE_SINGLE_TAB).EnableWindow(FALSE); + GetDlgItem(IDC_CHECK_TABS_ON_BOTTOM).EnableWindow(FALSE); if (m_nShowTabs > 0) { @@ -288,6 +297,16 @@ void DlgSettingsStyles::EnableTabControls() } } +void DlgSettingsStyles::EnableScrollbarControls() +{ + GetDlgItem(IDC_CHECK_FLAT_SCROLLBARS).EnableWindow(FALSE); + + if (m_nShowScrollbars > 0) + { + GetDlgItem(IDC_CHECK_FLAT_SCROLLBARS).EnableWindow(); + } +} + ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/DlgSettingsStyles.h b/Console/DlgSettingsStyles.h index 1f296b1e..5144a592 100644 --- a/Console/DlgSettingsStyles.h +++ b/Console/DlgSettingsStyles.h @@ -45,6 +45,7 @@ class DlgSettingsStyles COMMAND_ID_HANDLER(IDOK, OnCloseCmd) COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) COMMAND_HANDLER(IDC_CHECK_SHOW_TABS, BN_CLICKED, OnClickedShowTabs) + COMMAND_HANDLER(IDC_CHECK_SHOW_SCROLLBARS, BN_CLICKED, OnClickedShowScrollbars) COMMAND_HANDLER(IDC_KEY_COLOR, BN_CLICKED, OnClickedKeyColor) COMMAND_HANDLER(IDC_SELECTION_COLOR, BN_CLICKED, OnClickedSelColor) COMMAND_RANGE_CODE_HANDLER(IDC_TRANSPARENCY_TYPE, IDC_TRANSPARENCY_TYPE4, BN_CLICKED, OnClickedTransType) @@ -61,6 +62,7 @@ class DlgSettingsStyles LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnClickedShowTabs(WORD /*wNotifyCode*/, WORD /*wID*/, HWND hWndCtl, BOOL& /*bHandled*/); + LRESULT OnClickedShowScrollbars(WORD /*wNotifyCode*/, WORD /*wID*/, HWND hWndCtl, BOOL& /*bHandled*/); LRESULT OnClickedKeyColor(WORD /*wNotifyCode*/, WORD /*wID*/, HWND hWndCtl, BOOL& /*bHandled*/); LRESULT OnClickedSelColor(WORD /*wNotifyCode*/, WORD /*wID*/, HWND hWndCtl, BOOL& /*bHandled*/); LRESULT OnClickedTransType(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); @@ -69,6 +71,7 @@ class DlgSettingsStyles void UpdateSliderText(HWND hwnd); void EnableTabControls(); + void EnableScrollbarControls(); void EnableTransparencyControls(); private: From 52b6db01ca96c59c214faecac33808e94ce12e6d Mon Sep 17 00:00:00 2001 From: cbucher Date: Tue, 31 Aug 2010 19:02:18 +0200 Subject: [PATCH 008/207] close button in selected tab tooltip overlapping problem : tooltip's area for the selected tab is truncated at right where is the close button --- Console/AeroTabCtrl.h | 346 ++++++++++++++++++++++++++----- TabbingFramework/CustomTabCtrl.h | 21 +- 2 files changed, 313 insertions(+), 54 deletions(-) diff --git a/Console/AeroTabCtrl.h b/Console/AeroTabCtrl.h index 7db5d291..bfa40f5e 100644 --- a/Console/AeroTabCtrl.h +++ b/Console/AeroTabCtrl.h @@ -12,8 +12,10 @@ class CAeroTabCtrlImpl : signed char m_iLeftSpacing; signed char m_iTopMargin; signed char m_iRadius; + signed char m_iCloseButtonWidth; + signed char m_iCloseButtonHeight; -// Constructor + // Constructor public: CAeroTabCtrlImpl() @@ -24,7 +26,7 @@ class CAeroTabCtrlImpl : m_clrSelectedTab = ::GetSysColor(COLOR_WINDOW); } -// Message Handling + // Message Handling public: DECLARE_WND_CLASS_EX(_T("WTL_CAeroTabCtrl"), CS_DBLCLKS, COLOR_WINDOW) @@ -100,7 +102,7 @@ class CAeroTabCtrlImpl : return 0; } -// Overrides for painting from CDotNetTabCtrlImpl + // Overrides for painting from CDotNetTabCtrlImpl public: void DrawBackground(RECT /*rcClient*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw) @@ -228,6 +230,11 @@ class CAeroTabCtrlImpl : rcText.right -= m_iMargin; nIconVerticalCenter = (rcTab.bottom + rcTab.top - m_iTopMargin) / 2 + m_iTopMargin; } + + if (CTCS_CLOSEBUTTON == (dwStyle & CTCS_CLOSEBUTTON)) + { + rcText.right -= m_iCloseButtonWidth; + } } void DrawItem_TabInactive(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw, RECT& rcTab) @@ -302,24 +309,25 @@ class CAeroTabCtrlImpl : this->DrawTab(rcTab, g, tabcolor); //-------------------------------------------- - // This is how CDotNetTabCtrlImpl interprets padding, margin, etc.: + // This is how CAeroTabCtrlImpl interprets padding, margin, etc.: // // M - Margin // P - Padding // I - Image + // C - Close button // Text - Tab Text // - // With image: - // __________________________ + // With image & With close button: + // | M | I | P | Text | P | C | M | // - // | M | I | P | Text | P | M | - // -------------------------- + // Without image & With close Button : + // | M | P | Text | P | C | M | // - // Without image: - // ______________________ + // With image & Without close button: + // | M | I | P | Text | P | M | // + // Without image & Without close Button : // | M | P | Text | P | M | - // ---------------------- if (pItem->UsingImage() && !m_imageList.IsNull()) { @@ -380,17 +388,12 @@ class CAeroTabCtrlImpl : void DrawCloseButton(LPNMCTCCUSTOMDRAW lpNMCustomDraw) { - RECT zone; - zone.top = min(m_rcScrollLeft.top, m_rcCloseButton.top); - zone.left = m_rcScrollLeft.left; - zone.bottom = max(m_rcScrollLeft.bottom, m_rcCloseButton.bottom); - zone.right = m_rcCloseButton.right; + // drawed in the current tab HDC targetDC = lpNMCustomDraw->nmcd.hdc; HDC bufferedDC = NULL; BP_PAINTPARAMS m_PaintParams = { sizeof(BP_PAINTPARAMS) }; - HPAINTBUFFER pb = BeginBufferedPaint(targetDC, &zone, BPBF_TOPDOWNDIB, &m_PaintParams, &bufferedDC); - BufferedPaintClear(pb, &zone); + HPAINTBUFFER pb = BeginBufferedPaint(targetDC, &m_rcCloseButton, BPBF_TOPDOWNDIB, &m_PaintParams, &bufferedDC); int iStateCloseButton = CBS_NORMAL; if( ectcMouseDownL_CloseButton == (m_dwState & ectcMouseDown) ) @@ -410,6 +413,23 @@ class CAeroTabCtrlImpl : CloseThemeData(hTheme); + EndBufferedPaint(pb, TRUE); + } + + void DrawScrollButtons(LPNMCTCCUSTOMDRAW lpNMCustomDraw) + { + RECT zone; + zone.top = m_rcScrollLeft.top; + zone.left = m_rcScrollLeft.left; + zone.bottom = m_rcScrollLeft.bottom; + zone.right = m_rcScrollRight.right; + + HDC targetDC = lpNMCustomDraw->nmcd.hdc; + HDC bufferedDC = NULL; + BP_PAINTPARAMS m_PaintParams = { sizeof(BP_PAINTPARAMS) }; + HPAINTBUFFER pb = BeginBufferedPaint(targetDC, &zone, BPBF_TOPDOWNDIB, &m_PaintParams, &bufferedDC); + BufferedPaintClear(pb, &zone); + int iStateScrollLeft = NAV_BB_DISABLED; if( m_dwState & ectcOverflowLeft ) { @@ -430,7 +450,7 @@ class CAeroTabCtrlImpl : iStateScrollRight = NAV_FB_HOT; } - hTheme = OpenThemeData(m_hWnd, VSCLASS_NAVIGATION); + HTHEME hTheme = OpenThemeData(m_hWnd, VSCLASS_NAVIGATION); DrawThemeBackgroundEx( hTheme, @@ -453,11 +473,11 @@ class CAeroTabCtrlImpl : EndBufferedPaint(pb, TRUE); } - void DrawScrollButtons(LPNMCTCCUSTOMDRAW lpNMCustomDraw) + void CalcSize_CloseButton(LPRECT prcTabItemArea) { - } + DWORD dwStyle = this->GetStyle(); - void CalcSize_CloseButton(LPRECT prcTabItemArea) + if (CTCS_CLOSEBUTTON == (dwStyle & CTCS_CLOSEBUTTON)) { SIZE size; @@ -475,37 +495,14 @@ class CAeroTabCtrlImpl : CloseThemeData(hTheme); - if( (prcTabItemArea->right - prcTabItemArea->left) < size.cx ) - { - ::SetRectEmpty(&m_rcCloseButton); - return; - } - - m_rcCloseButton = *prcTabItemArea; - - DWORD dwStyle = this->GetStyle(); - - if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) - { - m_rcCloseButton.top += 3; + m_iCloseButtonWidth = size.cx; + m_iCloseButtonHeight = size.cy; } else { - m_rcCloseButton.top += 1; - m_rcCloseButton.bottom -= 2; + m_iCloseButtonWidth = 0; + m_iCloseButtonHeight = 0; } - m_rcCloseButton.top = (m_rcCloseButton.bottom + m_rcCloseButton.top - size.cy) / 2; - m_rcCloseButton.bottom = m_rcCloseButton.top + size.cy; - - m_rcCloseButton.left = m_rcCloseButton.right - (size.cx); - - if(m_tooltip.IsWindow()) - { - m_tooltip.SetToolRect(m_hWnd, (UINT)ectcToolTip_Close, &m_rcCloseButton); - } - - // Adjust the tab area - prcTabItemArea->right = m_rcCloseButton.left - 3; } void CalcSize_ScrollButtons(LPRECT prcTabItemArea) @@ -567,6 +564,255 @@ class CAeroTabCtrlImpl : prcTabItemArea->right = m_rcScrollLeft.left; } + void UpdateLayout_CloseButton(RECT rcItem) + { + RECT rcItemDP = {0}; + ::CopyRect(&rcItemDP, &rcItem); + ::OffsetRect(&rcItemDP, m_iScrollOffset, 0); + + int nIconVerticalCenter; + if (CTCS_BOTTOM == (this->GetStyle() & CTCS_BOTTOM)) + { + nIconVerticalCenter = (rcItemDP.bottom + rcItemDP.top - m_iTopMargin) / 2; + } + else + { + nIconVerticalCenter = (rcItemDP.bottom + rcItemDP.top - m_iTopMargin) / 2 + m_iTopMargin; + } + + // calculate the position of the close button + m_rcCloseButton.left = rcItemDP.right; + m_rcCloseButton.right = m_rcCloseButton.left + m_iCloseButtonWidth; + m_rcCloseButton.top = rcItemDP.top + nIconVerticalCenter - m_iCloseButtonHeight / 2; + m_rcCloseButton.bottom = m_rcCloseButton.top + m_iCloseButtonHeight; + + if(m_tooltip.IsWindow()) + { + m_tooltip.SetToolRect(m_hWnd, (UINT)ectcToolTip_Close, &m_rcCloseButton); + } + } + + void UpdateLayout_Default(RECT rcTabItemArea) + { + long nMinInactiveWidth = 0x7FFFFFFF; + long nMaxInactiveWidth = 0; + + WTL::CClientDC dc(m_hWnd); + HFONT hOldFont = dc.SelectFont(m_font); + + LONG nTabAreaWidth = (rcTabItemArea.right - rcTabItemArea.left); + + RECT rcItem = rcTabItemArea; + // rcItem.top and rcItem.bottom aren't really going to change + + // Recalculate tab positions and widths + // See DrawItem_ImageAndText for a discussion of how CDotNetTabCtrlImpl + // interprets margin, padding, etc. + size_t nCount = m_Items.GetCount(); + int xpos = m_settings.iIndent; + HFONT hRestoreNormalFont = NULL; + for( size_t i=0; iUsingImage() && !m_imageList.IsNull()) + { + IMAGEINFO ii = {0}; + int nImageIndex = pItem->GetImageIndex(); + m_imageList.GetImageInfo(nImageIndex, &ii); + rcItem.right += (ii.rcImage.right - ii.rcImage.left); + } + if(pItem->UsingText()) + { + rcItem.right += pItem->GetTextSize(dc) + (m_settings.iPadding * 2); + } + + // close button + if( bSelected ) + { + UpdateLayout_CloseButton(rcItem); + } + rcItem.right += m_iCloseButtonWidth; + + rcItem.right += m_settings.iMargin; + pItem->SetRect(rcItem); + xpos += (rcItem.right - rcItem.left); + + if(hRestoreNormalFont != NULL) + { + dc.SelectFont(hRestoreNormalFont); + hRestoreNormalFont = NULL; + } + + if(!bSelected) + { + if((rcItem.right - rcItem.left) < nMinInactiveWidth) + { + nMinInactiveWidth = (rcItem.right - rcItem.left); + } + if((rcItem.right - rcItem.left) > nMaxInactiveWidth) + { + nMaxInactiveWidth = (rcItem.right - rcItem.left); + } + } + } + xpos += m_settings.iIndent; + + if(xpos > nTabAreaWidth && nCount > 0 && m_iCurSel >= 0) + { + // Our desired widths are more than the width of the client area. + // We need to have some or all of the tabs give up some real estate + + // We'll try to let the selected tab have its fully desired width. + // If it can't, we'll make all the tabs the same width. + + RECT rcSelected = m_Items[m_iCurSel]->GetRect(); + LONG nSelectedWidth = (rcSelected.right - rcSelected.left); + + long cxClientInactiveTabs = nTabAreaWidth - (m_settings.iIndent * 2) - nSelectedWidth; + long cxDesiredInactiveTabs = xpos - (m_settings.iIndent * 2) - nSelectedWidth; + + double nRatioWithSelectionFullSize = 0.0; + if(cxDesiredInactiveTabs != 0) + { + nRatioWithSelectionFullSize = (double) (cxClientInactiveTabs) / (double)(cxDesiredInactiveTabs); + } + + long nInactiveSameSizeWidth = (m_nMinWidthToDisplayText + (m_settings.iMargin*2) + (m_settings.iPadding)); + + if(cxClientInactiveTabs > (nInactiveSameSizeWidth * (long)(nCount-1))) + { + // There should be enough room to display the entire contents of + // the selected tab plus something for the inactive tabs + + bool bMakeInactiveSameSize = ((nMinInactiveWidth * nRatioWithSelectionFullSize) < nInactiveSameSizeWidth); + + xpos = m_settings.iIndent; + for(size_t i=0; iGetRect(); + rcItem.left = rcItem.right = xpos; + if((int)i == m_iCurSel) + { + rcItem.right += (rcItemDesired.right - rcItemDesired.left); + } + else + { + if(bMakeInactiveSameSize && (nCount != 1)) + { + rcItem.right += (long)((cxClientInactiveTabs / (nCount-1)) + 0.5); + } + else + { + rcItem.right += (long)(((rcItemDesired.right - rcItemDesired.left) * nRatioWithSelectionFullSize) + 0.5); + } + } + pItem->SetRect(rcItem); + xpos += (rcItem.right-rcItem.left); + } + } + else + { + // We're down pretty small, so just make all the tabs the same width + int cxItem = (nTabAreaWidth - (m_settings.iIndent*2)) / (int)nCount; + + xpos = m_settings.iIndent; + + for(size_t i=0; iSetRect(rcItem); + xpos += (rcItem.right-rcItem.left); + } + } + } + + dc.SelectFont(hOldFont); + } + + void UpdateLayout_ScrollToFit(RECT rcTabItemArea) + { + // When we scroll to fit, we ignore what's passed in for the + // tab item area rect, and use the client rect instead + RECT rcClient; + this->GetClientRect(&rcClient); + + WTL::CClientDC dc(m_hWnd); + HFONT hOldFont = dc.SelectFont(m_font); + + RECT rcItem = rcClient; + + // Recalculate tab positions and widths + // See DrawItem_ImageAndText for a discussion of how CDotNetTabCtrlImpl + // interprets margin, padding, etc. + size_t nCount = m_Items.GetCount(); + int xpos = m_settings.iIndent; + HFONT hRestoreNormalFont = NULL; + for( size_t i=0; iUsingImage() && !m_imageList.IsNull()) + { + IMAGEINFO ii = {0}; + int nImageIndex = pItem->GetImageIndex(); + m_imageList.GetImageInfo(nImageIndex, &ii); + rcItem.right += (ii.rcImage.right - ii.rcImage.left); + } + if(pItem->UsingText()) + { + rcItem.right += pItem->GetTextSize(dc) + (m_settings.iPadding * 2); + } + + // close button + if( bSelected ) + { + UpdateLayout_CloseButton(rcItem); + } + rcItem.right += m_iCloseButtonWidth; + + rcItem.right += m_settings.iMargin; + pItem->SetRect(rcItem); + xpos += (rcItem.right - rcItem.left); + + if(hRestoreNormalFont != NULL) + { + dc.SelectFont(hRestoreNormalFont); + hRestoreNormalFont = NULL; + } + } + xpos += m_settings.iIndent; + + // If we've been scrolled to the left, and resize so + // there's more client area to the right, adjust the + // scroll offset accordingly. + if((xpos + m_iScrollOffset) < rcTabItemArea.right) + { + m_iScrollOffset = (rcTabItemArea.right - xpos); + } + + dc.SelectFont(hOldFont); + } + }; template @@ -577,7 +823,7 @@ class CAeroTabCtrl : typedef CAeroTabCtrl thisClass; typedef CAeroTabCtrlImpl, TItem> baseClass; -// Constructors: + // Constructors: public: CAeroTabCtrl() { diff --git a/TabbingFramework/CustomTabCtrl.h b/TabbingFramework/CustomTabCtrl.h index 7ea51565..0d508803 100644 --- a/TabbingFramework/CustomTabCtrl.h +++ b/TabbingFramework/CustomTabCtrl.h @@ -1438,8 +1438,10 @@ class ATL_NO_VTABLE CCustomTabCtrl : else if(ectcMouseInWindow == (m_dwState & ectcMouseInWindow)) { // hit test - if(::PtInRect(&m_rcCloseButton, ptCursor)) + bool boolHitNotFound = true; + if(boolHitNotFound && ::PtInRect(&m_rcCloseButton, ptCursor)) { + boolHitNotFound = false; if( ectcMouseOver_CloseButton != (m_dwState & ectcMouseOver)) { this->ClearCurrentMouseOverTracking(true); @@ -1470,8 +1472,9 @@ class ATL_NO_VTABLE CCustomTabCtrl : } } - if(::PtInRect(&m_rcScrollRight, ptCursor)) + if(boolHitNotFound && ::PtInRect(&m_rcScrollRight, ptCursor)) { + boolHitNotFound = false; if( ectcMouseOver_ScrollRight != (m_dwState & ectcMouseOver)) { this->ClearCurrentMouseOverTracking(true); @@ -1502,8 +1505,9 @@ class ATL_NO_VTABLE CCustomTabCtrl : } } - if(::PtInRect(&m_rcScrollLeft, ptCursor)) + if(boolHitNotFound && ::PtInRect(&m_rcScrollLeft, ptCursor)) { + boolHitNotFound = false; if( ectcMouseOver_ScrollLeft != (m_dwState & ectcMouseOver)) { this->ClearCurrentMouseOverTracking(true); @@ -1534,8 +1538,9 @@ class ATL_NO_VTABLE CCustomTabCtrl : } } - if(::PtInRect(&m_rcTabItemArea, ptCursor)) + if(boolHitNotFound && ::PtInRect(&m_rcTabItemArea, ptCursor)) { + boolHitNotFound = false; if( ectcMouseOver_TabItem != (m_dwState & ectcMouseOver)) { this->ClearCurrentMouseOverTracking(true); @@ -2383,6 +2388,14 @@ class ATL_NO_VTABLE CCustomTabCtrl : { RECT rcItemDP = {0}; this->GetItemRect(i, &rcItemDP); + + // we must remove the close button area + // the tooltip tools didn't support overlapping + if( m_rcCloseButton.left > rcItemDP.left && m_rcCloseButton.left < rcItemDP.right ) + { + rcItemDP.right = m_rcCloseButton.left - 1; + } + ::IntersectRect(&rcIntersect, &rcItemDP, &m_rcTabItemArea); // NOTE: Even if IntersectRect determines the rectangles From 7b89aaf98bd741eaf24c1bfef538a0781be4e511 Mon Sep 17 00:00:00 2001 From: cbucher Date: Wed, 1 Sep 2010 19:57:22 +0200 Subject: [PATCH 009/207] the hot tracking is used to pop the tooltip when mouse is over close button when mouse is over close button, OnGetToolTipInfo is called with id of the selected tab, but with the hot tracking status, the "Close" text is used --- Console/AeroTabCtrl.h | 36 +++++++++++++++++++++++++++----- TabbingFramework/CustomTabCtrl.h | 22 ++++++++++++------- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/Console/AeroTabCtrl.h b/Console/AeroTabCtrl.h index bfa40f5e..ca172ae8 100644 --- a/Console/AeroTabCtrl.h +++ b/Console/AeroTabCtrl.h @@ -497,6 +497,37 @@ class CAeroTabCtrlImpl : m_iCloseButtonWidth = size.cx; m_iCloseButtonHeight = size.cy; +/* + size_t nCount = m_Items.GetCount(); + if( m_iCurSel >=0 && (size_t)m_iCurSel < nCount ) + { + RECT rcItemLP = {0}, rcItemDP = {0}; + rcItemLP = m_Items[m_iCurSel]->GetRect(); + + ::CopyRect(&rcItemDP, &rcItemLP); + ::OffsetRect(&rcItemDP, m_iScrollOffset, 0); + + int nIconVerticalCenter; + if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) + { + nIconVerticalCenter = (rcItemDP.bottom + rcItemDP.top - m_iTopMargin) / 2; + } + else + { + nIconVerticalCenter = (rcItemDP.bottom + rcItemDP.top - m_iTopMargin) / 2 + m_iTopMargin; + } + + // calculate the position of the close button + m_rcCloseButton.right = rcItemDP.right - m_iMargin; + m_rcCloseButton.left = m_rcCloseButton.right - m_iCloseButtonWidth; + m_rcCloseButton.top = rcItemDP.top + nIconVerticalCenter - m_iCloseButtonHeight / 2; + m_rcCloseButton.bottom = m_rcCloseButton.top + m_iCloseButtonHeight; + + if(m_tooltip.IsWindow()) + { + m_tooltip.SetToolRect(m_hWnd, (UINT)ectcToolTip_Close, &m_rcCloseButton); + } + }*/ } else { @@ -585,11 +616,6 @@ class CAeroTabCtrlImpl : m_rcCloseButton.right = m_rcCloseButton.left + m_iCloseButtonWidth; m_rcCloseButton.top = rcItemDP.top + nIconVerticalCenter - m_iCloseButtonHeight / 2; m_rcCloseButton.bottom = m_rcCloseButton.top + m_iCloseButtonHeight; - - if(m_tooltip.IsWindow()) - { - m_tooltip.SetToolRect(m_hWnd, (UINT)ectcToolTip_Close, &m_rcCloseButton); - } } void UpdateLayout_Default(RECT rcTabItemArea) diff --git a/TabbingFramework/CustomTabCtrl.h b/TabbingFramework/CustomTabCtrl.h index 0d508803..7794c01f 100644 --- a/TabbingFramework/CustomTabCtrl.h +++ b/TabbingFramework/CustomTabCtrl.h @@ -1404,6 +1404,8 @@ class ATL_NO_VTABLE CCustomTabCtrl : DWORD dwStyle = this->GetStyle(); POINT ptCursor = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; + DWORD dwBefore = m_dwState & ectcHotTrack; + T* pT = static_cast(this); if(ectcMouseInWindow != (m_dwState & ectcMouseInWindow)) { @@ -1585,6 +1587,12 @@ class ATL_NO_VTABLE CCustomTabCtrl : } } + DWORD dwAfter = m_dwState & ectcHotTrack; + + if( dwAfter != dwBefore ) + if(m_tooltip.IsWindow()) + m_tooltip.Pop(); + return 1; } @@ -2160,6 +2168,12 @@ class ATL_NO_VTABLE CCustomTabCtrl : UINT_PTR id = pToolTipInfo->hdr.idFrom; if(id > 0 && id <= m_Items.GetCount()) { + if( (m_dwState & ectcHotTrack) == ectcHotTrack_CloseButton ) + { + pToolTipInfo->lpszText = _T("Close"); + } + else + { TItem* pItem = m_Items[id-1]; ATLASSERT(pItem != NULL); if(pItem) @@ -2175,6 +2189,7 @@ class ATL_NO_VTABLE CCustomTabCtrl : } } } + } return 0; } @@ -2389,13 +2404,6 @@ class ATL_NO_VTABLE CCustomTabCtrl : RECT rcItemDP = {0}; this->GetItemRect(i, &rcItemDP); - // we must remove the close button area - // the tooltip tools didn't support overlapping - if( m_rcCloseButton.left > rcItemDP.left && m_rcCloseButton.left < rcItemDP.right ) - { - rcItemDP.right = m_rcCloseButton.left - 1; - } - ::IntersectRect(&rcIntersect, &rcItemDP, &m_rcTabItemArea); // NOTE: Even if IntersectRect determines the rectangles From 328a9a7ea430c833d0ca55929b83876715239bf5 Mon Sep 17 00:00:00 2001 From: cbucher Date: Fri, 3 Sep 2010 21:23:11 +0200 Subject: [PATCH 010/207] no close button with only one tab --- Console/AeroTabCtrl.h | 39 +++++++-------------------------------- 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/Console/AeroTabCtrl.h b/Console/AeroTabCtrl.h index ca172ae8..96c75950 100644 --- a/Console/AeroTabCtrl.h +++ b/Console/AeroTabCtrl.h @@ -477,7 +477,7 @@ class CAeroTabCtrlImpl : { DWORD dwStyle = this->GetStyle(); - if (CTCS_CLOSEBUTTON == (dwStyle & CTCS_CLOSEBUTTON)) + if (CTCS_CLOSEBUTTON == (dwStyle & CTCS_CLOSEBUTTON) && m_Items.GetCount() > 1) { SIZE size; @@ -497,37 +497,6 @@ class CAeroTabCtrlImpl : m_iCloseButtonWidth = size.cx; m_iCloseButtonHeight = size.cy; -/* - size_t nCount = m_Items.GetCount(); - if( m_iCurSel >=0 && (size_t)m_iCurSel < nCount ) - { - RECT rcItemLP = {0}, rcItemDP = {0}; - rcItemLP = m_Items[m_iCurSel]->GetRect(); - - ::CopyRect(&rcItemDP, &rcItemLP); - ::OffsetRect(&rcItemDP, m_iScrollOffset, 0); - - int nIconVerticalCenter; - if (CTCS_BOTTOM == (dwStyle & CTCS_BOTTOM)) - { - nIconVerticalCenter = (rcItemDP.bottom + rcItemDP.top - m_iTopMargin) / 2; - } - else - { - nIconVerticalCenter = (rcItemDP.bottom + rcItemDP.top - m_iTopMargin) / 2 + m_iTopMargin; - } - - // calculate the position of the close button - m_rcCloseButton.right = rcItemDP.right - m_iMargin; - m_rcCloseButton.left = m_rcCloseButton.right - m_iCloseButtonWidth; - m_rcCloseButton.top = rcItemDP.top + nIconVerticalCenter - m_iCloseButtonHeight / 2; - m_rcCloseButton.bottom = m_rcCloseButton.top + m_iCloseButtonHeight; - - if(m_tooltip.IsWindow()) - { - m_tooltip.SetToolRect(m_hWnd, (UINT)ectcToolTip_Close, &m_rcCloseButton); - } - }*/ } else { @@ -597,6 +566,12 @@ class CAeroTabCtrlImpl : void UpdateLayout_CloseButton(RECT rcItem) { + if( m_Items.GetCount() < 1 ) + { + ::SetRectEmpty(&m_rcCloseButton); + return; + } + RECT rcItemDP = {0}; ::CopyRect(&rcItemDP, &rcItem); ::OffsetRect(&rcItemDP, m_iScrollOffset, 0); From 063e3025780451840b26c7c836c8e8563f6aef2a Mon Sep 17 00:00:00 2001 From: cbucher Date: Fri, 3 Sep 2010 21:24:11 +0200 Subject: [PATCH 011/207] confirmation on closing with multiple tabs --- Console/MainFrame.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 90cb3a19..d522b060 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -303,6 +303,9 @@ LRESULT MainFrame::OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPara LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { + if( m_views.size() > 1 && (::MessageBox(m_hWnd, L"Are you sure you want close all tabs ?", L"Close", MB_OKCANCEL | MB_ICONQUESTION) == IDCANCEL) ) + return 0; + // save settings on exit bool bSaveSettings = false; ConsoleSettings& consoleSettings = g_settingsHandler->GetConsoleSettings(); From 7608b799f214eaa2970ed0be9afa5502f3de8359 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 4 Sep 2010 11:54:34 +0200 Subject: [PATCH 012/207] all ways for closing a tab are disabled with only one tab --- Console/MainFrame.cpp | 31 ++++++++++++++----------------- Console/MainFrame.h | 2 +- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index d522b060..3803a761 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -219,6 +219,10 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, { MutexLock lock(m_viewsMutex); + if (m_views.size() == 1) + { + UIEnable(ID_FILE_CLOSE_TAB, FALSE); + } if ((m_views.size() == 1) && m_bTabsVisible && (controlsSettings.bHideSingleTab)) { ShowTabs(FALSE); @@ -1542,23 +1546,6 @@ LRESULT MainFrame::OnHelp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -/* - -shared_ptr MainFrame::GetActiveView() -{ - if (m_views.size() == 0) return shared_ptr(); - - ConsoleViewMap::iterator findIt = m_views.find(m_hWndActive); - if (findIt == m_views.end()) return shared_ptr(); - - return findIt->second; -} - -*/ -////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// void MainFrame::AdjustWindowRect(CRect& rect) @@ -1644,6 +1631,10 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir DisplayTab(hwndConsoleView, FALSE); ::SetForegroundWindow(m_hWnd); + if (m_views.size() > 1) + { + UIEnable(ID_FILE_CLOSE_TAB, TRUE); + } if ( g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowTabs && ((m_views.size() > 1) || (!g_settingsHandler->GetAppearanceSettings().controlsSettings.bHideSingleTab)) ) @@ -1661,7 +1652,9 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir void MainFrame::CloseTab(CTabViewTabItem* pTabItem) { + MutexLock viewMapLock(m_viewsMutex); if (!pTabItem) return; + if (m_views.size() <= 1) return; CloseTab(pTabItem->GetTabView()); } @@ -1681,6 +1674,10 @@ void MainFrame::CloseTab(HWND hwndConsoleView) it->second->DestroyWindow(); m_views.erase(it); + if (m_views.size() == 1) + { + UIEnable(ID_FILE_CLOSE_TAB, FALSE); + } if ((m_views.size() == 1) && m_bTabsVisible && (g_settingsHandler->GetAppearanceSettings().controlsSettings.bHideSingleTab)) diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 793d99f3..71b49d22 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -53,6 +53,7 @@ class MainFrame virtual BOOL OnIdle(); BEGIN_UPDATE_UI_MAP(MainFrame) + UPDATE_ELEMENT(ID_FILE_CLOSE_TAB, UPDUI_MENUPOPUP) UPDATE_ELEMENT(ID_VIEW_MENU, UPDUI_MENUPOPUP) UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP) UPDATE_ELEMENT(ID_VIEW_TABS, UPDUI_MENUPOPUP) @@ -95,7 +96,6 @@ class MainFrame COMMAND_RANGE_HANDLER(ID_NEW_TAB_1, ID_NEW_TAB_1 + 99, OnFileNewTab) COMMAND_ID_HANDLER(ID_FILE_NEW_TAB, OnFileNewTab) COMMAND_RANGE_HANDLER(ID_SWITCH_TAB_1, ID_SWITCH_TAB_1 + 9, OnSwitchTab) - COMMAND_ID_HANDLER(ID_FILE_CLOSE_TAB, OnFileCloseTab) COMMAND_ID_HANDLER(ID_NEXT_TAB, OnNextTab) COMMAND_ID_HANDLER(ID_PREV_TAB, OnPrevTab) COMMAND_ID_HANDLER(ID_FILE_CLOSE_TAB, OnFileCloseTab) From 814b33e757d4c59b4d12cbdb281d38a0f984792c Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 4 Sep 2010 22:05:35 +0200 Subject: [PATCH 013/207] add the tab icon in list of tab names (settings dialog) icon is refreshed at the fly --- Console/DlgSettingsTabs.cpp | 90 +++++++++++++++++++++++++++++++++-- Console/DlgSettingsTabs.h | 3 ++ Console/PageSettingsTabs1.cpp | 10 +++- Console/PageSettingsTabs1.h | 6 ++- 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/Console/DlgSettingsTabs.cpp b/Console/DlgSettingsTabs.cpp index 4cebd940..f3da2eef 100644 --- a/Console/DlgSettingsTabs.cpp +++ b/Console/DlgSettingsTabs.cpp @@ -35,17 +35,54 @@ DlgSettingsTabs::DlgSettingsTabs(CComPtr& pOptionsRoot) LRESULT DlgSettingsTabs::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { m_tabSettings.Load(m_pOptionsRoot); - + m_ImageList.Create(16, 16, ILC_COLOR32 | ILC_MASK, 4, 4); m_listCtrl.Attach(GetDlgItem(IDC_LIST_TABS)); m_listCtrl.SetExtendedListViewStyle(m_listCtrl.GetExtendedListViewStyle()|LVS_EX_FULLROWSELECT); m_listCtrl.InsertColumn(0, L"Tab name"); m_listCtrl.SetColumnWidth(0, 188); + m_listCtrl.SetImageList(m_ImageList, LVSIL_SMALL); + m_listCtrl.SetIconSpacing(16, 16); TabDataVector::iterator it = m_tabSettings.tabDataVector.begin(); for (; it != m_tabSettings.tabDataVector.end(); ++it) { - int nItem = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), (*it)->strTitle.c_str()); + CIcon tabSmallIcon; + if ((*it)->bUseDefaultIcon || ((*it)->strIcon.length() > 0)) + { + if ((*it)->strIcon.length() > 0) + { + tabSmallIcon.Attach( + static_cast( + ::LoadImage( + NULL, + Helpers::ExpandEnvironmentStrings((*it)->strIcon).c_str(), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR|LR_LOADFROMFILE + ) + ) + ); + } + else if ((*it)->bUseDefaultIcon) + { + tabSmallIcon.Attach( + static_cast( + ::LoadImage( + ::GetModuleHandle(NULL), + MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR + ) + ) + ); + } + } + int nIcon = tabSmallIcon.m_hIcon? m_ImageList.AddIcon(tabSmallIcon.m_hIcon) : -1; + int nItem = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), (*it)->strTitle.c_str(), nIcon); m_listCtrl.SetItemData(nItem, reinterpret_cast(it->get())); } @@ -87,6 +124,53 @@ LRESULT DlgSettingsTabs::OnTabTitleChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPA return 0; } +LRESULT DlgSettingsTabs::OnTabIconChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + wstring strIcon = m_page1.GetTabIcon(); + bool bUseDefaultIcon = m_page1.UseDefaultIcon() ? true : false; + + CIcon tabSmallIcon; + if (bUseDefaultIcon || (!strIcon.empty())) + { + if (!strIcon.empty()) + { + tabSmallIcon.Attach( + static_cast( + ::LoadImage( + NULL, + Helpers::ExpandEnvironmentStrings(strIcon).c_str(), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR|LR_LOADFROMFILE + ) + ) + ); + } + else if (bUseDefaultIcon) + { + tabSmallIcon.Attach( + static_cast( + ::LoadImage( + ::GetModuleHandle(NULL), + MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR + ) + ) + ); + } + } + int nIcon = tabSmallIcon.m_hIcon? m_ImageList.AddIcon(tabSmallIcon.m_hIcon) : -1; + // list control is not refreshed when an empty icon is set ... + // so the text is updated too ! + m_listCtrl.SetItem(m_listCtrl.GetSelectedIndex(), 0, LVIF_TEXT|LVIF_IMAGE, m_page1.GetTabTitle(), nIcon, 0, 0, 0); + + return 0; +} + ////////////////////////////////////////////////////////////////////////////// @@ -129,7 +213,7 @@ LRESULT DlgSettingsTabs::OnAdd(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt m_tabSettings.tabDataVector.push_back(tabData); - int nItem = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), tabData->strTitle.c_str()); + int nItem = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), tabData->strTitle.c_str(), -1); m_listCtrl.SetItemData(nItem, reinterpret_cast(tabData.get())); m_listCtrl.SelectItem(nItem); diff --git a/Console/DlgSettingsTabs.h b/Console/DlgSettingsTabs.h index a4d1cee4..71946359 100644 --- a/Console/DlgSettingsTabs.h +++ b/Console/DlgSettingsTabs.h @@ -28,6 +28,7 @@ class DlgSettingsTabs BEGIN_MSG_MAP(DlgSettingsTabs) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) MESSAGE_HANDLER(UM_TAB_TITLE_CHANGED, OnTabTitleChanged) + MESSAGE_HANDLER(UM_TAB_ICON_CHANGED, OnTabIconChanged) COMMAND_ID_HANDLER(IDOK, OnCloseCmd) COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) @@ -47,6 +48,7 @@ class DlgSettingsTabs LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnTabTitleChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnTabIconChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnAdd(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); @@ -66,6 +68,7 @@ class DlgSettingsTabs TabSettings m_tabSettings; CListViewCtrl m_listCtrl; + WTL::CImageList m_ImageList; CTabCtrl m_tabCtrl; PageSettingsTabs1 m_page1; diff --git a/Console/PageSettingsTabs1.cpp b/Console/PageSettingsTabs1.cpp index 3ca88296..14a65cc4 100644 --- a/Console/PageSettingsTabs1.cpp +++ b/Console/PageSettingsTabs1.cpp @@ -96,11 +96,17 @@ LRESULT PageSettingsTabs1::OnCtlColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM LRESULT PageSettingsTabs1::OnTabTitleChange(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { CWindow(GetDlgItem(IDC_TAB_TITLE)).GetWindowText(m_strTitle); -// GetParent().SendMessage(UM_TAB_TITLE_CHANGED, 0, 0); GetParent().PostMessage(UM_TAB_TITLE_CHANGED, 0, 0); return 0; } +LRESULT PageSettingsTabs1::OnTabIconChange(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + CWindow(GetDlgItem(IDC_TAB_ICON)).GetWindowText(m_strIcon); + GetParent().PostMessage(UM_TAB_ICON_CHANGED, 0, 0); + return 0; +} + ////////////////////////////////////////////////////////////////////////////// @@ -196,6 +202,8 @@ LRESULT PageSettingsTabs1::OnCheckDefaultIcon(WORD /*wNotifyCode*/, WORD /*wID*/ DoDataExchange(DDX_SAVE); EnableControls(); + GetParent().PostMessage(UM_TAB_ICON_CHANGED, 0, 0); + return 0; } diff --git a/Console/PageSettingsTabs1.h b/Console/PageSettingsTabs1.h index 44c7a89f..9aa7afbd 100644 --- a/Console/PageSettingsTabs1.h +++ b/Console/PageSettingsTabs1.h @@ -9,6 +9,7 @@ ////////////////////////////////////////////////////////////////////////////// #define UM_TAB_TITLE_CHANGED WM_USER + 0x2000 +#define UM_TAB_ICON_CHANGED WM_USER + 0x2001 ////////////////////////////////////////////////////////////////////////////// @@ -32,10 +33,10 @@ class PageSettingsTabs1 BEGIN_MSG_MAP(PageSettingsTabs1) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) -// MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnCtlColorStatic) COMMAND_HANDLER(IDC_TAB_TITLE, EN_CHANGE, OnTabTitleChange) + COMMAND_HANDLER(IDC_TAB_ICON, EN_CHANGE, OnTabIconChange) COMMAND_HANDLER(IDC_CURSOR_COLOR, BN_CLICKED, OnClickedCursorColor) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_ICON, OnBtnBrowseIcon) COMMAND_ID_HANDLER(IDC_CHECK_DEFAULT_ICON, OnCheckDefaultIcon) @@ -53,6 +54,7 @@ class PageSettingsTabs1 LRESULT OnCtlColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnTabTitleChange(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnTabIconChange(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnClickedCursorColor(WORD /*wNotifyCode*/, WORD /*wID*/, HWND hWndCtl, BOOL& /*bHandled*/); LRESULT OnBtnBrowseIcon(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnClickedBtnBrowseShell(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); @@ -65,6 +67,8 @@ class PageSettingsTabs1 void Save(); const CString& GetTabTitle() const { return m_strTitle; } + const CString& GetTabIcon() const { return m_strIcon; } + const int UseDefaultIcon() const { return m_nUseDefaultIcon; } private: From 56e1d57216a63136ab41a7418c641034a5b29acf Mon Sep 17 00:00:00 2001 From: cbucher Date: Mon, 6 Sep 2010 02:03:04 +0200 Subject: [PATCH 014/207] fix tabs settings background are not saved --- Console/PageSettingsTabs2.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Console/PageSettingsTabs2.cpp b/Console/PageSettingsTabs2.cpp index 992d726e..e30c494f 100644 --- a/Console/PageSettingsTabs2.cpp +++ b/Console/PageSettingsTabs2.cpp @@ -283,6 +283,20 @@ void PageSettingsTabs2::Load(shared_ptr& tabData) void PageSettingsTabs2::Save() { DoDataExchange(DDX_SAVE); + + m_tabData->backgroundImageType = static_cast(m_nBkType); + + if (m_tabData->backgroundImageType != bktypeNone) + { + m_tabData->crBackgroundColor = RGB(0, 0, 0); + } + + m_tabData->imageData.strFilename = m_strBkImage; + m_tabData->imageData.bRelative = m_nRelative > 0; + m_tabData->imageData.bExtend = m_nExtend > 0; + + m_tabData->imageData.imagePosition = static_cast(m_comboBkPosition.GetCurSel()); + m_tabData->imageData.byTintOpacity = static_cast(m_sliderTintOpacity.GetPos()); } ////////////////////////////////////////////////////////////////////////////// From f8d2b37a6ed6d9a0baed6b12e33772919a30c262 Mon Sep 17 00:00:00 2001 From: cbucher Date: Mon, 6 Sep 2010 02:14:38 +0200 Subject: [PATCH 015/207] add clone button in settings of tabs --- Console/Console.rc | 12 ++++++------ Console/DlgSettingsTabs.cpp | 25 ++++++++++++++++++++++++- Console/DlgSettingsTabs.h | 4 +++- Console/resource.h | 1 + 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index 4c07b758..e5a8277c 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -437,10 +437,11 @@ STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_LIST_TABS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,0,128,75 - PUSHBUTTON "Add",IDC_BTN_ADD,130,5,50,14 - PUSHBUTTON "Delete",IDC_BTN_DELETE,130,22,50,14 - PUSHBUTTON "Move up",IDC_BTN_UP,130,39,50,14 - PUSHBUTTON "Move down",IDC_BTN_DOWN,130,56,50,14 + PUSHBUTTON "Add",IDC_BTN_ADD,129,0,50,14 + PUSHBUTTON "Clone",IDC_BTN_CLONE,129,14,50,14 + PUSHBUTTON "Delete",IDC_BTN_DELETE,129,28,50,14 + PUSHBUTTON "Move up",IDC_BTN_UP,130,46,50,14 + PUSHBUTTON "Move down",IDC_BTN_DOWN,130,61,50,14 CONTROL "",IDC_TABS,"SysTabControl32",WS_TABSTOP,0,80,232,185 END @@ -919,8 +920,7 @@ END // // Generated from the TEXTINCLUDE 3 resource. // - - + ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/Console/DlgSettingsTabs.cpp b/Console/DlgSettingsTabs.cpp index f3da2eef..9b6e31fe 100644 --- a/Console/DlgSettingsTabs.cpp +++ b/Console/DlgSettingsTabs.cpp @@ -35,7 +35,7 @@ DlgSettingsTabs::DlgSettingsTabs(CComPtr& pOptionsRoot) LRESULT DlgSettingsTabs::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { m_tabSettings.Load(m_pOptionsRoot); - m_ImageList.Create(16, 16, ILC_COLOR32 | ILC_MASK, 4, 4); + m_ImageList.Create(16, 16, ILC_COLOR32 | ILC_MASK, 4, 4); m_listCtrl.Attach(GetDlgItem(IDC_LIST_TABS)); m_listCtrl.SetExtendedListViewStyle(m_listCtrl.GetExtendedListViewStyle()|LVS_EX_FULLROWSELECT); @@ -225,6 +225,29 @@ LRESULT DlgSettingsTabs::OnAdd(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +LRESULT DlgSettingsTabs::OnClone(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + int nItem = m_listCtrl.GetSelectedIndex(); + + m_page1.Save(); + m_page2.Save(); + + shared_ptr tabData(new TabData(*(m_tabSettings.tabDataVector[nItem].get()))); + + m_tabSettings.tabDataVector.insert(m_tabSettings.tabDataVector.begin() + nItem + 1, tabData); + int nItemClone = m_listCtrl.InsertItem(nItem + 1, tabData->strTitle.c_str(), -1); + m_listCtrl.SetItemData(nItemClone, reinterpret_cast(tabData.get())); + + m_listCtrl.SelectItem(nItemClone); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// LRESULT DlgSettingsTabs::OnUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) diff --git a/Console/DlgSettingsTabs.h b/Console/DlgSettingsTabs.h index 71946359..10f51917 100644 --- a/Console/DlgSettingsTabs.h +++ b/Console/DlgSettingsTabs.h @@ -33,6 +33,7 @@ class DlgSettingsTabs COMMAND_ID_HANDLER(IDOK, OnCloseCmd) COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) COMMAND_ID_HANDLER(IDC_BTN_ADD, OnAdd) + COMMAND_ID_HANDLER(IDC_BTN_CLONE, OnClone) COMMAND_ID_HANDLER(IDC_BTN_DELETE, OnDelete) COMMAND_ID_HANDLER(IDC_BTN_UP, OnUp) COMMAND_ID_HANDLER(IDC_BTN_DOWN, OnDown) @@ -52,6 +53,7 @@ class DlgSettingsTabs LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnAdd(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnClone(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnDelete(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); @@ -68,7 +70,7 @@ class DlgSettingsTabs TabSettings m_tabSettings; CListViewCtrl m_listCtrl; - WTL::CImageList m_ImageList; + WTL::CImageList m_ImageList; CTabCtrl m_tabCtrl; PageSettingsTabs1 m_page1; diff --git a/Console/resource.h b/Console/resource.h index 7f22ffc0..989d8047 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -170,6 +170,7 @@ #define IDC_BTN_DOWN 1136 #define IDC_BTN_DELETE 1137 #define IDC_STATIC_BK_COLOR 1138 +#define IDC_BTN_CLONE 1138 #define IDC_STATIC_TINT_COLOR 1139 #define IDC_STATIC_BK_IMAGE 1140 #define IDC_STATIC_BK_POS 1141 From 4b421291adaf9092382716756b3667a233b257e3 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 11 Sep 2010 09:09:50 +0200 Subject: [PATCH 016/207] helpers method to load a small icon --- Console/DlgSettingsTabs.cpp | 70 ++----------------------------------- Console/Helpers.cpp | 40 +++++++++++++++++++++ Console/Helpers.h | 2 ++ 3 files changed, 44 insertions(+), 68 deletions(-) diff --git a/Console/DlgSettingsTabs.cpp b/Console/DlgSettingsTabs.cpp index 9b6e31fe..d91f6d90 100644 --- a/Console/DlgSettingsTabs.cpp +++ b/Console/DlgSettingsTabs.cpp @@ -47,40 +47,7 @@ LRESULT DlgSettingsTabs::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM / TabDataVector::iterator it = m_tabSettings.tabDataVector.begin(); for (; it != m_tabSettings.tabDataVector.end(); ++it) { - CIcon tabSmallIcon; - if ((*it)->bUseDefaultIcon || ((*it)->strIcon.length() > 0)) - { - if ((*it)->strIcon.length() > 0) - { - tabSmallIcon.Attach( - static_cast( - ::LoadImage( - NULL, - Helpers::ExpandEnvironmentStrings((*it)->strIcon).c_str(), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR|LR_LOADFROMFILE - ) - ) - ); - } - else if ((*it)->bUseDefaultIcon) - { - tabSmallIcon.Attach( - static_cast( - ::LoadImage( - ::GetModuleHandle(NULL), - MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR - ) - ) - ); - } - } + CIcon tabSmallIcon(Helpers::LoadSmallIcon((*it)->bUseDefaultIcon, (*it)->strIcon)); int nIcon = tabSmallIcon.m_hIcon? m_ImageList.AddIcon(tabSmallIcon.m_hIcon) : -1; int nItem = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), (*it)->strTitle.c_str(), nIcon); m_listCtrl.SetItemData(nItem, reinterpret_cast(it->get())); @@ -129,40 +96,7 @@ LRESULT DlgSettingsTabs::OnTabIconChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPAR wstring strIcon = m_page1.GetTabIcon(); bool bUseDefaultIcon = m_page1.UseDefaultIcon() ? true : false; - CIcon tabSmallIcon; - if (bUseDefaultIcon || (!strIcon.empty())) - { - if (!strIcon.empty()) - { - tabSmallIcon.Attach( - static_cast( - ::LoadImage( - NULL, - Helpers::ExpandEnvironmentStrings(strIcon).c_str(), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR|LR_LOADFROMFILE - ) - ) - ); - } - else if (bUseDefaultIcon) - { - tabSmallIcon.Attach( - static_cast( - ::LoadImage( - ::GetModuleHandle(NULL), - MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR - ) - ) - ); - } - } + CIcon tabSmallIcon(Helpers::LoadSmallIcon(bUseDefaultIcon, strIcon)); int nIcon = tabSmallIcon.m_hIcon? m_ImageList.AddIcon(tabSmallIcon.m_hIcon) : -1; // list control is not refreshed when an empty icon is set ... // so the text is updated too ! diff --git a/Console/Helpers.cpp b/Console/Helpers.cpp index 7d9141bb..f03dac09 100644 --- a/Console/Helpers.cpp +++ b/Console/Helpers.cpp @@ -137,3 +137,43 @@ HBITMAP Helpers::CreateBitmap(HDC dc, DWORD dwWidth, DWORD dwHeight, CBitmap& bi ////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// + +HICON Helpers::LoadSmallIcon(bool bUseDefaultIcon, wstring strIcon) +{ + if (bUseDefaultIcon || (!strIcon.empty())) + { + if (!strIcon.empty()) + { + return static_cast( + ::LoadImage( + NULL, + Helpers::ExpandEnvironmentStrings(strIcon).c_str(), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR|LR_LOADFROMFILE + ) + ); + } + else if (bUseDefaultIcon) + { + return static_cast( + ::LoadImage( + ::GetModuleHandle(NULL), + MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, + 16, + 16, + LR_DEFAULTCOLOR + ) + ); + } + } + + return NULL; +} + +////////////////////////////////////////////////////////////////////////////// + diff --git a/Console/Helpers.h b/Console/Helpers.h index 0e451d73..c4c1de1c 100644 --- a/Console/Helpers.h +++ b/Console/Helpers.h @@ -24,6 +24,8 @@ class Helpers static HBITMAP CreateBitmap(HDC dc, DWORD dwWidth, DWORD dwHeight, CBitmap& bitmap); + static HICON LoadSmallIcon(bool bUseDefaultIcon, wstring strIcon); + private: static void GetMonitorRect(HMONITOR hMonitor, bool bIgnoreTaskbar, CRect& rectDesktop); From 7da11531170d3cbcf08d87eec7c3b09a5261df3e Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 11 Sep 2010 10:51:51 +0200 Subject: [PATCH 017/207] default icon is shell executable icon --- Console/ConsoleView.cpp | 38 +-------------- Console/DlgSettingsTabs.cpp | 7 +-- Console/Helpers.cpp | 65 +++++++++++++++++++++---- Console/Helpers.h | 2 +- Console/MainFrame.cpp | 97 +++++-------------------------------- Console/PageSettingsTabs1.h | 1 + Console/stdafx.h | 1 + 7 files changed, 77 insertions(+), 134 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 30b1227d..4d79b95a 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -113,42 +113,8 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam* DragAcceptFiles(TRUE); // load icon - if (m_tabData->strIcon.length() > 0) - { - bigIcon = static_cast(::LoadImage( - NULL, - Helpers::ExpandEnvironmentStrings(m_tabData->strIcon).c_str(), - IMAGE_ICON, - 0, - 0, - LR_DEFAULTCOLOR|LR_LOADFROMFILE|LR_DEFAULTSIZE)); - - smallIcon = static_cast(::LoadImage( - NULL, - Helpers::ExpandEnvironmentStrings(m_tabData->strIcon).c_str(), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR|LR_LOADFROMFILE)); - } - else - { - bigIcon = static_cast(::LoadImage( - ::GetModuleHandle(NULL), - MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, - 0, - 0, - LR_DEFAULTCOLOR|LR_DEFAULTSIZE)); - - smallIcon = static_cast(::LoadImage( - ::GetModuleHandle(NULL), - MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR)); - } + bigIcon.Attach(Helpers::LoadTabIcon(true, m_tabData->bUseDefaultIcon, m_tabData->strIcon, m_tabData->strShell)); + smallIcon.Attach(Helpers::LoadTabIcon(false, m_tabData->bUseDefaultIcon, m_tabData->strIcon, m_tabData->strShell)); // set console delegates m_consoleHandler.SetupDelegates( diff --git a/Console/DlgSettingsTabs.cpp b/Console/DlgSettingsTabs.cpp index d91f6d90..0be2d762 100644 --- a/Console/DlgSettingsTabs.cpp +++ b/Console/DlgSettingsTabs.cpp @@ -47,7 +47,7 @@ LRESULT DlgSettingsTabs::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM / TabDataVector::iterator it = m_tabSettings.tabDataVector.begin(); for (; it != m_tabSettings.tabDataVector.end(); ++it) { - CIcon tabSmallIcon(Helpers::LoadSmallIcon((*it)->bUseDefaultIcon, (*it)->strIcon)); + CIcon tabSmallIcon(Helpers::LoadTabIcon(false, (*it)->bUseDefaultIcon, (*it)->strIcon, (*it)->strShell)); int nIcon = tabSmallIcon.m_hIcon? m_ImageList.AddIcon(tabSmallIcon.m_hIcon) : -1; int nItem = m_listCtrl.InsertItem(m_listCtrl.GetItemCount(), (*it)->strTitle.c_str(), nIcon); m_listCtrl.SetItemData(nItem, reinterpret_cast(it->get())); @@ -93,10 +93,11 @@ LRESULT DlgSettingsTabs::OnTabTitleChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPA LRESULT DlgSettingsTabs::OnTabIconChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { - wstring strIcon = m_page1.GetTabIcon(); bool bUseDefaultIcon = m_page1.UseDefaultIcon() ? true : false; + wstring strIcon = m_page1.GetTabIcon(); + wstring strShell = m_page1.GetTabShell(); - CIcon tabSmallIcon(Helpers::LoadSmallIcon(bUseDefaultIcon, strIcon)); + CIcon tabSmallIcon(Helpers::LoadTabIcon(false, bUseDefaultIcon, strIcon, strShell)); int nIcon = tabSmallIcon.m_hIcon? m_ImageList.AddIcon(tabSmallIcon.m_hIcon) : -1; // list control is not refreshed when an empty icon is set ... // so the text is updated too ! diff --git a/Console/Helpers.cpp b/Console/Helpers.cpp index f03dac09..bc677b2d 100644 --- a/Console/Helpers.cpp +++ b/Console/Helpers.cpp @@ -140,11 +140,46 @@ HBITMAP Helpers::CreateBitmap(HDC dc, DWORD dwWidth, DWORD dwHeight, CBitmap& bi ////////////////////////////////////////////////////////////////////////////// -HICON Helpers::LoadSmallIcon(bool bUseDefaultIcon, wstring strIcon) +HICON Helpers::LoadTabIcon(bool bBigIcon, bool bUseDefaultIcon, const wstring& strIcon, const wstring& strShell) { - if (bUseDefaultIcon || (!strIcon.empty())) + if (bUseDefaultIcon) { - if (!strIcon.empty()) + if ( !strShell.empty() ) + { + wstring strCommandLine = Helpers::ExpandEnvironmentStrings(strShell); + int argc = 0; + LPWSTR* argv = ::CommandLineToArgvW(strCommandLine.c_str(), &argc); + if ( argv && argc > 0 ) + { + SHFILEINFO info; + memset(&info, 0, sizeof(info)); + if( ::SHGetFileInfo( + argv[0], + 0, + &info, + sizeof(info), + SHGFI_ICON | (( bBigIcon )? SHGFI_LARGEICON : SHGFI_SMALLICON)) != 0 ) + { + return info.hIcon; + } + } + ::LocalFree(argv); + } + } + else if (!strIcon.empty()) + { + if ( bBigIcon ) + { + return static_cast( + ::LoadImage( + NULL, + Helpers::ExpandEnvironmentStrings(strIcon).c_str(), + IMAGE_ICON, + 0, + 0, + LR_DEFAULTCOLOR | LR_LOADFROMFILE | LR_DEFAULTSIZE)); + } + else { return static_cast( ::LoadImage( @@ -153,11 +188,23 @@ HICON Helpers::LoadSmallIcon(bool bUseDefaultIcon, wstring strIcon) IMAGE_ICON, 16, 16, - LR_DEFAULTCOLOR|LR_LOADFROMFILE - ) - ); + LR_DEFAULTCOLOR | LR_LOADFROMFILE)); + } + } + else + { + if ( bBigIcon ) + { + return static_cast( + ::LoadImage( + ::GetModuleHandle(NULL), + MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, + 0, + 0, + LR_DEFAULTCOLOR | LR_DEFAULTSIZE)); } - else if (bUseDefaultIcon) + else { return static_cast( ::LoadImage( @@ -166,9 +213,7 @@ HICON Helpers::LoadSmallIcon(bool bUseDefaultIcon, wstring strIcon) IMAGE_ICON, 16, 16, - LR_DEFAULTCOLOR - ) - ); + LR_DEFAULTCOLOR)); } } diff --git a/Console/Helpers.h b/Console/Helpers.h index c4c1de1c..90b329ca 100644 --- a/Console/Helpers.h +++ b/Console/Helpers.h @@ -24,7 +24,7 @@ class Helpers static HBITMAP CreateBitmap(HDC dc, DWORD dwWidth, DWORD dwHeight, CBitmap& bitmap); - static HICON LoadSmallIcon(bool bUseDefaultIcon, wstring strIcon); + static HICON LoadTabIcon(bool bBigIcon, bool bUseDefaultIcon, const wstring& strIcon, const wstring& strShell); private: diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 3803a761..ae90e977 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1715,58 +1715,21 @@ void MainFrame::UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu) tabsMenu.InsertMenuItem(dwId-ID_NEW_TAB_1, TRUE, &subMenuItem); // create menu icons with proper transparency (thanks to chrisz for the patch) - CIcon tabSmallIcon; - - if ((*it)->bUseDefaultIcon || ((*it)->strIcon.length() > 0)) - { - if ((*it)->menuBitmap.IsNull()) - { + CIcon tabSmallIcon(Helpers::LoadTabIcon(false, (*it)->bUseDefaultIcon, (*it)->strIcon, (*it)->strShell)); - if ((*it)->strIcon.length() > 0) - { - tabSmallIcon.Attach( - static_cast( - ::LoadImage( - NULL, - Helpers::ExpandEnvironmentStrings((*it)->strIcon).c_str(), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR|LR_LOADFROMFILE - ) - ) - ); - } - else if ((*it)->bUseDefaultIcon) - { - tabSmallIcon.Attach( - static_cast( - ::LoadImage( - ::GetModuleHandle(NULL), - MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR - ) - ) - ); - } + // destroy icon bitmap + if (!(*it)->menuBitmap.IsNull()) (*it)->menuBitmap.DeleteObject(); - CDC dc; + if (!tabSmallIcon.IsNull()) + { + CDC dc; - (*it)->menuBitmap.CreateCompatibleBitmap(::GetDC(NULL), 16, 16); + (*it)->menuBitmap.CreateCompatibleBitmap(::GetDC(NULL), 16, 16); - dc.CreateCompatibleDC(::GetDC(NULL)); - dc.SelectBitmap((*it)->menuBitmap); - dc.FillSolidRect(0, 0, 16, 16, ::GetSysColor(COLOR_MENU)); - dc.DrawIconEx(0, 0, tabSmallIcon.m_hIcon, 16, 16); - } - } - else - { - // destroy icon bitmap - if (!(*it)->menuBitmap.IsNull()) (*it)->menuBitmap.DeleteObject(); + dc.CreateCompatibleDC(::GetDC(NULL)); + dc.SelectBitmap((*it)->menuBitmap); + dc.FillSolidRect(0, 0, 16, 16, ::GetSysColor(COLOR_MENU)); + dc.DrawIconEx(0, 0, tabSmallIcon.m_hIcon, 16, 16); } if (!(*it)->menuBitmap.IsNull()) @@ -1958,42 +1921,8 @@ void MainFrame::SetWindowIcons() } else { - if (windowSettings.strIcon.length() > 0) - { - m_icon.Attach(static_cast(::LoadImage( - NULL, - Helpers::ExpandEnvironmentStrings(windowSettings.strIcon).c_str(), - IMAGE_ICON, - 0, - 0, - LR_DEFAULTCOLOR | LR_LOADFROMFILE | LR_DEFAULTSIZE))); - - m_smallIcon.Attach(static_cast(::LoadImage( - NULL, - Helpers::ExpandEnvironmentStrings(windowSettings.strIcon).c_str(), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR | LR_LOADFROMFILE))); - } - else - { - m_icon.Attach(static_cast(::LoadImage( - ::GetModuleHandle(NULL), - MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, - 0, - 0, - LR_DEFAULTCOLOR | LR_DEFAULTSIZE))); - - m_smallIcon.Attach(static_cast(::LoadImage( - ::GetModuleHandle(NULL), - MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, - 16, - 16, - LR_DEFAULTCOLOR))); - } + m_icon.Attach(Helpers::LoadTabIcon(true, false, windowSettings.strIcon, L"")); + m_smallIcon.Attach(Helpers::LoadTabIcon(false, false, windowSettings.strIcon, L"")); } if (!m_icon.IsNull()) diff --git a/Console/PageSettingsTabs1.h b/Console/PageSettingsTabs1.h index 9aa7afbd..5ed4ff6e 100644 --- a/Console/PageSettingsTabs1.h +++ b/Console/PageSettingsTabs1.h @@ -68,6 +68,7 @@ class PageSettingsTabs1 const CString& GetTabTitle() const { return m_strTitle; } const CString& GetTabIcon() const { return m_strIcon; } + const CString& GetTabShell() const { return m_strShell; } const int UseDefaultIcon() const { return m_nUseDefaultIcon; } private: diff --git a/Console/stdafx.h b/Console/stdafx.h index 1989418e..07c26e28 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -70,6 +70,7 @@ extern CAppModule _Module; #pragma warning(pop) #include +#include #pragma warning(disable: 4503) // disables 'name truncated' warnings From d34f57209735f111b1e7698a33043566141ab8e6 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 11 Sep 2010 17:58:52 +0200 Subject: [PATCH 018/207] DrawIconEx is the better way to draw an icon with smooth edges --- Console/AeroTabCtrl.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Console/AeroTabCtrl.h b/Console/AeroTabCtrl.h index 96c75950..f41e900d 100644 --- a/Console/AeroTabCtrl.h +++ b/Console/AeroTabCtrl.h @@ -339,14 +339,16 @@ class CAeroTabCtrlImpl : if((ii.rcImage.right - ii.rcImage.left) < (rcTab.right - rcTab.left)) { int nImageHalfHeight = (ii.rcImage.bottom - ii.rcImage.top) / 2; - CIcon icon; - icon.Attach(m_imageList.ExtractIcon(nImageIndex)); - Gdiplus::Bitmap bitmap(icon.m_hIcon); - - g.DrawImage( - &bitmap, - rcText.left, - nIconVerticalCenter - nImageHalfHeight + m_nFontSizeTextTopOffset); + + CIcon tabSmallIcon(m_imageList.ExtractIcon(nImageIndex)); + if( !tabSmallIcon.IsNull() ) + { + WTL::CDCHandle dc(bufferedDC); + dc.DrawIconEx( + rcText.left, nIconVerticalCenter - nImageHalfHeight + m_nFontSizeTextTopOffset, + tabSmallIcon.m_hIcon, + 16, 16); + } } // Offset on the right of the image. From c8420d444de4b33bdf5049babdf4a2cc56c900ab Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 12 Sep 2010 23:26:22 +0200 Subject: [PATCH 019/207] fix MainFrame::OnTabMiddleClick : LPARAM type is NMCTCITEM (not NMCTC2ITEMS) --- Console/MainFrame.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index ae90e977..19d6f76c 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1123,23 +1123,22 @@ LRESULT MainFrame::OnTabClose(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /* bHandled */ LRESULT MainFrame::OnTabMiddleClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) { - NMCTC2ITEMS* pTabItems = reinterpret_cast(pnmh); - CTabViewTabItem* pTabItem = (pTabItems->iItem1 != 0xFFFFFFFF) ? m_TabCtrl.GetItem(pTabItems->iItem1) : NULL; + NMCTCITEM* pTabItems = reinterpret_cast(pnmh); + CTabViewTabItem* pTabItem = (pTabItems->iItem != 0xFFFFFFFF) ? m_TabCtrl.GetItem(pTabItems->iItem) : NULL; if (pTabItem == NULL) { - // I prefer choose my console with the good environment ... + // I prefer choose my console with the good environment ... // CreateNewConsole(0); - - if (!m_tabsMenu.IsNull()) - { - // a priori y a une petite inversion X et Y ... - CPoint point(pTabItems->pt.y, pTabItems->pt.x); - CPoint screenPoint(point); - this->m_TabCtrl.ClientToScreen(&screenPoint); - m_tabsMenu.TrackPopupMenu(0, screenPoint.x, screenPoint.y, m_hWnd); - } + + if (!m_tabsMenu.IsNull()) + { + CPoint point(pTabItems->pt.x, pTabItems->pt.y); + CPoint screenPoint(point); + this->m_TabCtrl.ClientToScreen(&screenPoint); + m_tabsMenu.TrackPopupMenu(0, screenPoint.x, screenPoint.y, m_hWnd); + } } else { From 7b382afd6b8d593f253bde99d743bf4beec58df9 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Tue, 24 Aug 2010 19:43:40 +0200 Subject: [PATCH 020/207] Removed a 'fix' from 38cb482e commit - was causing problems on Win7 x64 --- ConsoleHook/ConsoleHandler.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index 99ba3177..e0f9c6ab 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -129,19 +129,20 @@ void ConsoleHandler::ReadConsoleBuffer() // we take a fresh STDOUT handle - seems to work better (in case a program // has opened a new screen output buffer) // no need to call CloseHandle when done, we're reusing console handles - HANDLE hStdOut = ::CreateFile( - L"CONOUT$", - GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - 0, - 0); + shared_ptr hStdOut(::CreateFile( + L"CONOUT$", + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + 0), + ::CloseHandle); CONSOLE_SCREEN_BUFFER_INFO csbiConsole; COORD coordConsoleSize; - ::GetConsoleScreenBufferInfo(hStdOut, &csbiConsole); + ::GetConsoleScreenBufferInfo(hStdOut.get(), &csbiConsole); coordConsoleSize.X = csbiConsole.srWindow.Right - csbiConsole.srWindow.Left + 1; coordConsoleSize.Y = csbiConsole.srWindow.Bottom - csbiConsole.srWindow.Top + 1; @@ -188,7 +189,7 @@ void ConsoleHandler::ReadConsoleBuffer() // TRACE(L"Reading region: (%i, %i) - (%i, %i)\n", srBuffer.Left, srBuffer.Top, srBuffer.Right, srBuffer.Bottom); ::ReadConsoleOutput( - hStdOut, + hStdOut.get(), pScreenBuffer.get() + dwScreenBufferOffset, coordBufferSize, coordStart, @@ -212,7 +213,7 @@ void ConsoleHandler::ReadConsoleBuffer() */ ::ReadConsoleOutput( - hStdOut, + hStdOut.get(), pScreenBuffer.get() + dwScreenBufferOffset, coordBufferSize, coordStart, @@ -232,7 +233,7 @@ void ConsoleHandler::ReadConsoleBuffer() m_dwScreenBufferSize = dwScreenBufferSize; ::CopyMemory(m_consoleBuffer.Get(), pScreenBuffer.get(), m_dwScreenBufferSize*sizeof(CHAR_INFO)); ::CopyMemory(m_consoleInfo.Get(), &csbiConsole, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); - ::GetConsoleCursorInfo(hStdOut, m_cursorInfo.Get()); + ::GetConsoleCursorInfo(hStdOut.get(), m_cursorInfo.Get()); m_consoleBuffer.SetReqEvent(); } From 94d00301edaf6ba4af93f50e7a8f2a29aa74103f Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Thu, 26 Aug 2010 11:46:23 +0100 Subject: [PATCH 021/207] Paste command is now disabled if a text selection is active. Copy and clear selection commands are disabled if there is no selection active. --- Console/ConsoleView.h | 4 ++++ Console/MainFrame.cpp | 9 +++++++++ Console/MainFrame.h | 9 ++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index a4bfdf6e..76989e3a 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -127,6 +127,10 @@ class ConsoleView void ClearSelection(); void Paste(); + bool CanCopy() const { return m_selectionHandler->GetState() == SelectionHandler::selstateSelected; } + bool CanClearSelection() const { return m_selectionHandler->GetState() > SelectionHandler::selstateNoSelection; } + bool CanPaste() const { return (m_selectionHandler->GetState() == SelectionHandler::selstateNoSelection) && (::IsClipboardFormatAvailable(CF_UNICODETEXT) || ::IsClipboardFormatAvailable(CF_TEXT) || ::IsClipboardFormatAvailable(CF_OEMTEXT)) ; } + void DumpBuffer(); void InitializeScrollbars(); diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 19d6f76c..958cdc0e 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -91,6 +91,14 @@ BOOL MainFrame::OnIdle() { UpdateStatusBar(); UIUpdateToolBar(); + + if (m_activeView.get() != NULL) + { + UIEnable(ID_EDIT_COPY, m_activeView->CanCopy() ? TRUE : FALSE); + UIEnable(ID_EDIT_CLEAR_SELECTION, m_activeView->CanClearSelection() ? TRUE : FALSE); + UIEnable(ID_EDIT_PASTE, m_activeView->CanPaste() ? TRUE : FALSE); + } + return FALSE; } @@ -209,6 +217,7 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, UISetCheck(ID_VIEW_TOOLBAR, 1); UISetCheck(ID_VIEW_TABS, 1); UISetCheck(ID_VIEW_STATUS_BAR, 1); + UISetBlockAccelerators(true); SetWindowStyles(); diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 71b49d22..613425d2 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -54,6 +54,9 @@ class MainFrame BEGIN_UPDATE_UI_MAP(MainFrame) UPDATE_ELEMENT(ID_FILE_CLOSE_TAB, UPDUI_MENUPOPUP) + UPDATE_ELEMENT(ID_EDIT_COPY, UPDUI_MENUPOPUP) + UPDATE_ELEMENT(ID_EDIT_CLEAR_SELECTION, UPDUI_MENUPOPUP) + UPDATE_ELEMENT(ID_EDIT_PASTE, UPDUI_MENUPOPUP) UPDATE_ELEMENT(ID_VIEW_MENU, UPDUI_MENUPOPUP) UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP) UPDATE_ELEMENT(ID_VIEW_TABS, UPDUI_MENUPOPUP) @@ -88,11 +91,15 @@ class MainFrame MESSAGE_HANDLER(UM_SHOW_POPUP_MENU, OnShowPopupMenu) MESSAGE_HANDLER(UM_START_MOUSE_DRAG, OnStartMouseDrag) MESSAGE_HANDLER(UM_TRAY_NOTIFY, OnTrayNotify) + NOTIFY_CODE_HANDLER(CTCN_SELCHANGE, OnTabChanged) NOTIFY_CODE_HANDLER(CTCN_CLOSE, OnTabClose) NOTIFY_CODE_HANDLER(CTCN_MCLICK, OnTabMiddleClick); NOTIFY_CODE_HANDLER(RBN_HEIGHTCHANGE, OnRebarHeightChanged) NOTIFY_HANDLER(ATL_IDW_TOOLBAR, TBN_DROPDOWN, OnToolbarDropDown) + + CHAIN_MSG_MAP(CUpdateUI) + COMMAND_RANGE_HANDLER(ID_NEW_TAB_1, ID_NEW_TAB_1 + 99, OnFileNewTab) COMMAND_ID_HANDLER(ID_FILE_NEW_TAB, OnFileNewTab) COMMAND_RANGE_HANDLER(ID_SWITCH_TAB_1, ID_SWITCH_TAB_1 + 9, OnSwitchTab) @@ -114,7 +121,7 @@ class MainFrame COMMAND_ID_HANDLER(ID_HELP, OnHelp) COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout) COMMAND_ID_HANDLER(IDC_DUMP_BUFFER, OnDumpBuffer) - CHAIN_MSG_MAP(CUpdateUI) + CHAIN_MSG_MAP(CTabbedFrameImpl) REFLECT_NOTIFICATIONS() END_MSG_MAP() From 885d25dc02918fa73180d52916b6d22bb85646de Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Thu, 26 Aug 2010 14:33:35 +0100 Subject: [PATCH 022/207] A bit of code cleanup --- Console/ConsoleHandler.cpp | 4 ++-- Console/ConsoleView.cpp | 4 ++-- Console/ImageHandler.cpp | 2 +- Console/MainFrame.cpp | 26 +++++++++++++------------- shared/SharedMemory.h | 16 ++++++++-------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 9131e9cc..145e290e 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -387,7 +387,7 @@ bool ConsoleHandler::InjectHookDLL() PAGE_READWRITE)), bind(::VirtualFreeEx, m_hConsoleProcess.get(), _1, NULL, MEM_RELEASE)); - if (pszHookDllPathRemote.get() == NULL) return false; + if (!pszHookDllPathRemote) return false; // write the memory if (!::WriteProcessMemory( @@ -416,7 +416,7 @@ bool ConsoleHandler::InjectHookDLL() NULL), ::CloseHandle); - if (hRemoteThread.get() == NULL) return false; + if (!hRemoteThread) return false; // wait for the thread to finish // ::WaitForSingleObject(hRemoteThread.get(), INFINITE); diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 4d79b95a..cd391ac3 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -131,7 +131,7 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam* m_background = g_imageHandler->GetDesktopImage(m_tabData->imageData); } - if (m_background.get() == NULL) m_tabData->backgroundImageType = bktypeNone; + if (!m_background) m_tabData->backgroundImageType = bktypeNone; // TODO: error handling wstring strInitialDir(m_consoleSettings.strInitialDir); @@ -1925,7 +1925,7 @@ void ConsoleView::BitBltOffscreen(bool bOnlyCursor /*= false*/) if (bOnlyCursor) { // blit only cursor - if ((m_cursor.get() == NULL) || !m_consoleHandler.GetCursorInfo()->bVisible) return; + if (!(m_cursor) || !m_consoleHandler.GetCursorInfo()->bVisible) return; SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); diff --git a/Console/ImageHandler.cpp b/Console/ImageHandler.cpp index 780fb552..b1b9c652 100644 --- a/Console/ImageHandler.cpp +++ b/Console/ImageHandler.cpp @@ -207,7 +207,7 @@ bool ImageHandler::LoadImage(shared_ptr& bkImage) CriticalSectionLock lock(bkImage->updateCritSec); - if (bkImage.get() == NULL) return false; + if (!bkImage) return false; // if we're reloading, delete old bitmap and DC if (!bkImage->dcImage.IsNull()) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 958cdc0e..c4660674 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -77,7 +77,7 @@ BOOL MainFrame::PreTranslateMessage(MSG* pMsg) if(CTabbedFrameImpl::PreTranslateMessage(pMsg)) return TRUE; - if (m_activeView.get() == NULL) return FALSE; + if (!m_activeView) return FALSE; return m_activeView->PreTranslateMessage(pMsg); } @@ -373,7 +373,7 @@ LRESULT MainFrame::OnActivateApp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/ { BOOL bActivating = static_cast(wParam); - if (m_activeView.get() == NULL) return 0; + if (!m_activeView) return 0; m_activeView->SetAppActiveStatus(bActivating ? true : false); @@ -547,7 +547,7 @@ LRESULT MainFrame::OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lPar CRect maxClientRect; - if ((m_activeView.get() == NULL) || (!m_activeView->GetMaxRect(maxClientRect))) + if (!(m_activeView) || (!m_activeView->GetMaxRect(maxClientRect))) { bHandled = false; return 1; @@ -1281,7 +1281,7 @@ LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + if (!m_activeView) return 0; m_activeView->Paste(); @@ -1295,7 +1295,7 @@ LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, LRESULT MainFrame::OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + if (!m_activeView) return 0; m_activeView->Copy(); @@ -1309,7 +1309,7 @@ LRESULT MainFrame::OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + if (!m_activeView) return 0; m_activeView->ClearSelection(); @@ -1323,7 +1323,7 @@ LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + if (!m_activeView) return 0; m_activeView->Paste(); @@ -1337,7 +1337,7 @@ LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt LRESULT MainFrame::OnEditStopScrolling(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + if (!m_activeView) return 0; m_activeView->GetConsoleHandler().StopScrolling(); @@ -1351,7 +1351,7 @@ LRESULT MainFrame::OnEditStopScrolling(WORD /*wNotifyCode*/, WORD /*wID*/, HWND LRESULT MainFrame::OnEditRenameTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + if (!m_activeView) return 0; DlgRenameTab dlg(m_activeView->GetTitle()); @@ -1387,7 +1387,7 @@ LRESULT MainFrame::OnEditRenameTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hW LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + if (!m_activeView) return 0; DlgSettingsMain dlg; @@ -1528,7 +1528,7 @@ LRESULT MainFrame::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnDumpBuffer(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() == NULL) return 0; + if (!m_activeView) return 0; m_activeView->DumpBuffer(); @@ -2100,7 +2100,7 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal } // adjust the active view - if (m_activeView.get() == NULL) return; + if (!m_activeView) return; // if we're being maximized, AdjustRectAndResize will use client rect supplied m_activeView->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge, !bMaxOrRestore); @@ -2126,7 +2126,7 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal } else { - if (m_activeView.get() == NULL) return; + if (!m_activeView) return; CRect maxClientRect; m_activeView->GetMaxRect(maxClientRect); m_activeView->GetRect(clientRect); diff --git a/shared/SharedMemory.h b/shared/SharedMemory.h index c84f84ba..706c82eb 100644 --- a/shared/SharedMemory.h +++ b/shared/SharedMemory.h @@ -159,7 +159,7 @@ void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTyp ::CloseHandle); // TODO: error handling - //if (m_hSharedMem.get() == NULL) return false; + //if (!m_hSharedMem) return false; m_pSharedMem = shared_ptr(static_cast(::MapViewOfFile( m_hSharedMem.get(), @@ -173,7 +173,7 @@ void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTyp if (syncObjects > syncObjNone) CreateSyncObjects(syncObjects, strName); - //if (m_pSharedMem.get() == NULL) return false; + //if (!m_pSharedMem) return false; } ////////////////////////////////////////////////////////////////////////////// @@ -193,7 +193,7 @@ void SharedMemory::Open(const wstring& strName, SyncObjectTypes syncObjects) ::CloseHandle); // TODO: error handling - //if (m_hSharedMem.get() == NULL) return false; + //if (!m_hSharedMem) return false; m_pSharedMem = shared_ptr(static_cast(::MapViewOfFile( m_hSharedMem.get(), @@ -205,7 +205,7 @@ void SharedMemory::Open(const wstring& strName, SyncObjectTypes syncObjects) if (syncObjects > syncObjNone) CreateSyncObjects(syncObjects, strName); - //if (m_pSharedMem.get() == NULL) return false; + //if (!m_pSharedMem) return false; } ////////////////////////////////////////////////////////////////////////////// @@ -216,7 +216,7 @@ void SharedMemory::Open(const wstring& strName, SyncObjectTypes syncObjects) template void SharedMemory::Lock() { - if (m_hSharedMutex.get() == NULL) return; + if (!m_hSharedMutex) return; ::WaitForSingleObject(m_hSharedMutex.get(), INFINITE); } @@ -228,7 +228,7 @@ void SharedMemory::Lock() template void SharedMemory::Release() { - if (m_hSharedMutex.get() == NULL) return; + if (!m_hSharedMutex) return; ::ReleaseMutex(m_hSharedMutex.get()); } @@ -240,7 +240,7 @@ void SharedMemory::Release() template void SharedMemory::SetReqEvent() { - if (m_hSharedReqEvent.get() == NULL) return; + if (!m_hSharedReqEvent) return; ::SetEvent(m_hSharedReqEvent.get()); } @@ -252,7 +252,7 @@ void SharedMemory::SetReqEvent() template void SharedMemory::SetRespEvent() { - if (m_hSharedRespEvent.get() == NULL) return; + if (!m_hSharedRespEvent) return; ::SetEvent(m_hSharedRespEvent.get()); } From 031bd8f60ea30cd03f93fc9431bf93da0631c976 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Thu, 26 Aug 2010 16:36:07 +0200 Subject: [PATCH 023/207] A fix for blinking tabs after unlock (BR #2990729) --- Console/ConsoleHandler.cpp | 8 ++--- Console/ConsoleHandler.h | 4 +-- Console/ConsoleView.cpp | 57 +++++++++++++++++++++------------- Console/SelectionHandler.cpp | 8 ++--- Console/SelectionHandler.h | 4 +-- Console/stdafx.h | 3 ++ ConsoleHook/ConsoleHandler.cpp | 21 +++++++++---- ConsoleHook/ConsoleHandler.h | 2 +- shared/Structures.h | 17 ++++++++++ 9 files changed, 83 insertions(+), 41 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 145e290e..621a5edd 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -457,10 +457,10 @@ DWORD ConsoleHandler::MonitorThread() HANDLE arrWaitHandles[] = { m_hConsoleProcess.get(), m_hMonitorThreadExit.get(), m_consoleBuffer.GetReqEvent() }; while (::WaitForMultipleObjects(sizeof(arrWaitHandles)/sizeof(arrWaitHandles[0]), arrWaitHandles, FALSE, INFINITE) > WAIT_OBJECT_0 + 1) { - DWORD dwColumns = m_consoleInfo->srWindow.Right - m_consoleInfo->srWindow.Left + 1; - DWORD dwRows = m_consoleInfo->srWindow.Bottom - m_consoleInfo->srWindow.Top + 1; - DWORD dwBufferColumns = m_consoleInfo->dwSize.X; - DWORD dwBufferRows = m_consoleInfo->dwSize.Y; + DWORD dwColumns = m_consoleInfo->csbi.srWindow.Right - m_consoleInfo->csbi.srWindow.Left + 1; + DWORD dwRows = m_consoleInfo->csbi.srWindow.Bottom - m_consoleInfo->csbi.srWindow.Top + 1; + DWORD dwBufferColumns = m_consoleInfo->csbi.dwSize.X; + DWORD dwBufferRows = m_consoleInfo->csbi.dwSize.Y; bool bResize = false; if ((m_consoleParams->dwColumns != dwColumns) || diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index d33acd68..441271c7 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -30,7 +30,7 @@ class ConsoleHandler shared_ptr GetConsoleHandle() const { return m_hConsoleProcess; } SharedMemory& GetConsoleParams() { return m_consoleParams; } - SharedMemory& GetConsoleInfo() { return m_consoleInfo; } + SharedMemory& GetConsoleInfo() { return m_consoleInfo; } SharedMemory& GetCursorInfo() { return m_cursorInfo; } SharedMemory& GetConsoleBuffer() { return m_consoleBuffer; } SharedMemory& GetCopyInfo() { return m_consoleCopyInfo; } @@ -70,7 +70,7 @@ class ConsoleHandler shared_ptr m_hConsoleProcess; SharedMemory m_consoleParams; - SharedMemory m_consoleInfo; + SharedMemory m_consoleInfo; SharedMemory m_cursorInfo; SharedMemory m_consoleBuffer; SharedMemory m_consoleCopyInfo; diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index cd391ac3..9d34d07e 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -748,7 +748,8 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* { if (m_bInitializing) return false; - bool bResize = (wParam == 1); + bool bResize = ((wParam & UPDATE_CONSOLE_RESIZE) > 0); + bool textChanged= ((wParam & UPDATE_CONSOLE_TEXT_CHANGED) > 0); // console size changed, resize offscreen buffers if (bResize) @@ -768,7 +769,7 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* UpdateTitle(); // if the view is not visible, don't repaint - if (!m_bActive) + if (!m_bActive && textChanged) { if ((!bResize) && (g_settingsHandler->GetBehaviorSettings().tabHighlightSettings.dwFlashes > 0) && @@ -781,19 +782,19 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* return 0; } - SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); + SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); if (m_bShowVScroll) { SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_POS; - si.nPos = consoleInfo->srWindow.Top; + si.nPos = consoleInfo->csbi.srWindow.Top; ::FlatSB_SetScrollInfo(m_hWnd, SB_VERT, &si, TRUE); /* TRACE(L"----------------------------------------------------------------\n"); - TRACE(L"VScroll pos: %i\n", consoleInfo->srWindow.Top); + TRACE(L"VScroll pos: %i\n", consoleInfo->csbi.srWindow.Top); */ } @@ -802,7 +803,7 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_POS; - si.nPos = consoleInfo->srWindow.Left; + si.nPos = consoleInfo->csbi.srWindow.Left; ::FlatSB_SetScrollInfo(m_hWnd, SB_HORZ, &si, TRUE); } @@ -1258,8 +1259,10 @@ void ConsoleView::OnConsoleChange(bool bResize) SharedMemory& consoleParams = m_consoleHandler.GetConsoleParams(); DWORD dwBufferSize = consoleParams->dwRows * consoleParams->dwColumns; + SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); SharedMemory& consoleBuffer = m_consoleHandler.GetConsoleBuffer(); + SharedMemoryLock consoleInfoLock(consoleInfo); SharedMemoryLock sharedBufferLock(consoleBuffer); MutexLock localBufferLock(m_bufferMutex); @@ -1279,7 +1282,17 @@ void ConsoleView::OnConsoleChange(bool bResize) } } - PostMessage(UM_UPDATE_CONSOLE_VIEW, bResize ? 1 : 0); + WPARAM wParam = 0; + + if (bResize) wParam |= UPDATE_CONSOLE_RESIZE; + + if (consoleInfo->textChanged) + { + wParam |= UPDATE_CONSOLE_TEXT_CHANGED; + consoleInfo->textChanged = false; + } + + PostMessage(UM_UPDATE_CONSOLE_VIEW, wParam); } ////////////////////////////////////////////////////////////////////////////// @@ -1927,13 +1940,13 @@ void ConsoleView::BitBltOffscreen(bool bOnlyCursor /*= false*/) // blit only cursor if (!(m_cursor) || !m_consoleHandler.GetCursorInfo()->bVisible) return; - SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); + SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); rectBlit = m_cursor->GetCursorRect(); - rectBlit.left += (consoleInfo->dwCursorPosition.X - consoleInfo->srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; - rectBlit.top += (consoleInfo->dwCursorPosition.Y - consoleInfo->srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; - rectBlit.right += (consoleInfo->dwCursorPosition.X - consoleInfo->srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; - rectBlit.bottom += (consoleInfo->dwCursorPosition.Y - consoleInfo->srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; + rectBlit.left += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; + rectBlit.top += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; + rectBlit.right += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; + rectBlit.bottom += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; } else { @@ -1973,20 +1986,20 @@ void ConsoleView::UpdateOffscreen(const CRect& rectBlit) if (m_consoleHandler.GetCursorInfo()->bVisible && (m_cursor.get() != NULL)) { CRect rectCursor(0, 0, 0, 0); - SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); + SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; // don't blit if cursor is outside visible window - if ((consoleInfo->dwCursorPosition.X >= consoleInfo->srWindow.Left) && - (consoleInfo->dwCursorPosition.X <= consoleInfo->srWindow.Right) && - (consoleInfo->dwCursorPosition.Y >= consoleInfo->srWindow.Top) && - (consoleInfo->dwCursorPosition.Y <= consoleInfo->srWindow.Bottom)) + if ((consoleInfo->csbi.dwCursorPosition.X >= consoleInfo->csbi.srWindow.Left) && + (consoleInfo->csbi.dwCursorPosition.X <= consoleInfo->csbi.srWindow.Right) && + (consoleInfo->csbi.dwCursorPosition.Y >= consoleInfo->csbi.srWindow.Top) && + (consoleInfo->csbi.dwCursorPosition.Y <= consoleInfo->csbi.srWindow.Bottom)) { rectCursor = m_cursor->GetCursorRect(); - rectCursor.left += (consoleInfo->dwCursorPosition.X - consoleInfo->srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; - rectCursor.top += (consoleInfo->dwCursorPosition.Y - consoleInfo->srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; - rectCursor.right += (consoleInfo->dwCursorPosition.X - consoleInfo->srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; - rectCursor.bottom += (consoleInfo->dwCursorPosition.Y - consoleInfo->srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; + rectCursor.left += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; + rectCursor.top += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; + rectCursor.right += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; + rectCursor.bottom += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; m_cursor->BitBlt( m_dcOffscreen, @@ -2236,7 +2249,7 @@ COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint) DWORD dwColumns = m_consoleHandler.GetConsoleParams()->dwColumns; DWORD dwBufferColumns = m_consoleHandler.GetConsoleParams()->dwBufferColumns; - SMALL_RECT& srWindow = m_consoleHandler.GetConsoleInfo()->srWindow; + SMALL_RECT& srWindow = m_consoleHandler.GetConsoleInfo()->csbi.srWindow; CPoint point(clientPoint); COORD consolePoint; diff --git a/Console/SelectionHandler.cpp b/Console/SelectionHandler.cpp index f8a4cd17..a5365186 100644 --- a/Console/SelectionHandler.cpp +++ b/Console/SelectionHandler.cpp @@ -19,7 +19,7 @@ SelectionHandler::SelectionHandler( const CRect& rectConsoleView, ConsoleHandler& consoleHandler, SharedMemory& consoleParams, - SharedMemory& consoleInfo, + SharedMemory& consoleInfo, SharedMemory& consoleCopyInfo, int nCharWidth, int nCharHeight) @@ -82,7 +82,7 @@ void SelectionHandler::StartSelection(const COORD& coordInit, COLORREF crSelecti m_coordCurrent.X = m_coordInitial.X; m_coordCurrent.Y = m_coordInitial.Y; - SMALL_RECT& srWindow = m_consoleInfo->srWindow; + SMALL_RECT& srWindow = m_consoleInfo->csbi.srWindow; int nDeltaX = m_coordCurrent.X - srWindow.Left; int nDeltaY = m_coordCurrent.Y - srWindow.Top; @@ -117,7 +117,7 @@ void SelectionHandler::UpdateSelection(const COORD& coordCurrent, shared_arraysrWindow; + SMALL_RECT& srWindow = m_consoleInfo->csbi.srWindow; int nDeltaX = m_coordCurrent.X - srWindow.Left; int nDeltaY = m_coordCurrent.Y - srWindow.Top; @@ -378,7 +378,7 @@ void SelectionHandler::GetSelectionCoordinates(COORD& coordStart, COORD& coordEn void SelectionHandler::GetFillRect(const COORD& coordStart, const COORD& coordEnd, CRect& fillRect) { StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; - SMALL_RECT& srWindow = m_consoleInfo->srWindow; + SMALL_RECT& srWindow = m_consoleInfo->csbi.srWindow; CRect rectConsoleView; m_consoleView.GetClientRect(&rectConsoleView); diff --git a/Console/SelectionHandler.h b/Console/SelectionHandler.h index 3c639a00..bda6d791 100644 --- a/Console/SelectionHandler.h +++ b/Console/SelectionHandler.h @@ -29,7 +29,7 @@ class SelectionHandler const CRect& rectConsoleView, ConsoleHandler& consoleHandler, SharedMemory& consoleParams, - SharedMemory& consoleInfo, + SharedMemory& consoleInfo, SharedMemory& consoleCopyInfo, int nCharWidth, int nCharHeight); @@ -66,7 +66,7 @@ class SelectionHandler ConsoleHandler& m_consoleHandler; SharedMemory& m_consoleParams; - SharedMemory& m_consoleInfo; + SharedMemory& m_consoleInfo; SharedMemory& m_consoleCopyInfo; int m_nCharWidth; int m_nCharHeight; diff --git a/Console/stdafx.h b/Console/stdafx.h index 07c26e28..052ac785 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -149,6 +149,9 @@ using namespace boost::multi_index; #define UM_START_MOUSE_DRAG WM_USER + 0x1005 #define UM_TRAY_NOTIFY WM_USER + 0x1006 +#define UPDATE_CONSOLE_RESIZE 0x0001 +#define UPDATE_CONSOLE_TEXT_CHANGED 0x0002 + #define IDC_TRAY_ICON 0x0001 ////////////////////////////////////////////////////////////////////////////// diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index e0f9c6ab..bd9ecc43 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -223,16 +223,25 @@ void ConsoleHandler::ReadConsoleBuffer() // TRACE(L"===================================================================\n"); // compare previous buffer, and if different notify Console - if ((::memcmp(m_consoleInfo.Get(), &csbiConsole, sizeof(CONSOLE_SCREEN_BUFFER_INFO)) != 0) || + SharedMemoryLock consoleInfoLock(m_consoleInfo); + SharedMemoryLock bufferLock(m_consoleBuffer); + + bool textChanged = (::memcmp(m_consoleBuffer.Get(), pScreenBuffer.get(), m_dwScreenBufferSize*sizeof(CHAR_INFO)) != 0); + + if ((::memcmp(&m_consoleInfo->csbi, &csbiConsole, sizeof(CONSOLE_SCREEN_BUFFER_INFO)) != 0) || (m_dwScreenBufferSize != dwScreenBufferSize) || - (::memcmp(m_consoleBuffer.Get(), pScreenBuffer.get(), m_dwScreenBufferSize*sizeof(CHAR_INFO)) != 0)) + textChanged) { - SharedMemoryLock bufferLock(m_consoleBuffer); - // update screen buffer variables m_dwScreenBufferSize = dwScreenBufferSize; + + ::CopyMemory(&m_consoleInfo->csbi, &csbiConsole, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); + + // only Console sets the flag to false, after it's done repainting text + if (textChanged) m_consoleInfo->textChanged = true; + ::CopyMemory(m_consoleBuffer.Get(), pScreenBuffer.get(), m_dwScreenBufferSize*sizeof(CHAR_INFO)); - ::CopyMemory(m_consoleInfo.Get(), &csbiConsole, sizeof(CONSOLE_SCREEN_BUFFER_INFO)); + ::GetConsoleCursorInfo(hStdOut.get(), m_cursorInfo.Get()); m_consoleBuffer.SetReqEvent(); @@ -734,7 +743,7 @@ void ConsoleHandler::SetConsoleParams(DWORD dwHookThreadId, HANDLE hStdOut) TRACE(L"Max columns: %i, max rows: %i\n", m_consoleParams->dwMaxColumns, m_consoleParams->dwMaxRows); // get initial window and cursor info - ::GetConsoleScreenBufferInfo(hStdOut, m_consoleInfo.Get()); + ::GetConsoleScreenBufferInfo(hStdOut, &m_consoleInfo->csbi); ::GetConsoleCursorInfo(hStdOut, m_cursorInfo.Get()); m_consoleParams.SetReqEvent(); diff --git a/ConsoleHook/ConsoleHandler.h b/ConsoleHook/ConsoleHandler.h index 2e0ea330..0e87e756 100644 --- a/ConsoleHook/ConsoleHandler.h +++ b/ConsoleHook/ConsoleHandler.h @@ -51,7 +51,7 @@ class ConsoleHandler shared_ptr m_hParentProcess; SharedMemory m_consoleParams; - SharedMemory m_consoleInfo; + SharedMemory m_consoleInfo; SharedMemory m_cursorInfo; SharedMemory m_consoleBuffer; SharedMemory m_consoleCopyInfo; diff --git a/shared/Structures.h b/shared/Structures.h index 126cd496..356b3c88 100644 --- a/shared/Structures.h +++ b/shared/Structures.h @@ -128,6 +128,23 @@ struct ConsoleCopy ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +struct ConsoleInfo +{ + ConsoleInfo() + : csbi() + , textChanged(false) + { + } + + CONSOLE_SCREEN_BUFFER_INFO csbi; + bool textChanged; +}; + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// struct CharInfo From 9775ea67202154384bdcb32076a6b2d3fb0171cc Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Thu, 2 Sep 2010 20:20:54 +0100 Subject: [PATCH 024/207] New inject code, x64 doesn't seem to work properly --- Console/Console.vcproj | 4 +- Console/ConsoleHandler.cpp | 218 +++++++++++++++++++++++++++++++- Console/ConsoleHandler.h | 2 +- Console2.sln | 8 ++ ConsoleHook/ConsoleHook.vcproj | 4 +- ConsoleWow/ConsoleWow.cpp | 12 ++ ConsoleWow/ConsoleWow.vcproj | 225 +++++++++++++++++++++++++++++++++ ConsoleWow/ReadMe.txt | 33 +++++ ConsoleWow/stdafx.cpp | 8 ++ ConsoleWow/stdafx.h | 12 ++ ConsoleWow/targetver.h | 13 ++ 11 files changed, 532 insertions(+), 7 deletions(-) create mode 100644 ConsoleWow/ConsoleWow.cpp create mode 100644 ConsoleWow/ConsoleWow.vcproj create mode 100644 ConsoleWow/ReadMe.txt create mode 100644 ConsoleWow/stdafx.cpp create mode 100644 ConsoleWow/stdafx.h create mode 100644 ConsoleWow/targetver.h diff --git a/Console/Console.vcproj b/Console/Console.vcproj index 9c1fff4a..c205ccfa 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -148,7 +148,7 @@ AdditionalOptions="/Zm200" Optimization="0" AdditionalIncludeDirectories="../TabbingFramework;../wtl/wtl/include" - PreprocessorDefinitions="WIN32;_WINDOWS;STRICT;_DEBUG" + PreprocessorDefinitions="_WIN64;_WINDOWS;STRICT;_DEBUG" MinimalRebuild="false" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -328,7 +328,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/Zm200" AdditionalIncludeDirectories="../TabbingFramework;../wtl/wtl/include" - PreprocessorDefinitions="WIN32;_WINDOWS;STRICT;NDEBUG" + PreprocessorDefinitions="_WIN64;_WINDOWS;STRICT;NDEBUG" ExceptionHandling="1" RuntimeLibrary="0" UsePrecompiledHeader="2" diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 621a5edd..f3b76fff 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -200,7 +200,7 @@ bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstr m_hConsoleProcess = shared_ptr(pi.hProcess, ::CloseHandle); // inject our hook DLL into console process - if (!InjectHookDLL()) return false; + if (!InjectHookDLL(pi)) return false; // resume the console process ::ResumeThread(pi.hThread); @@ -370,13 +370,226 @@ bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId) ////////////////////////////////////////////////////////////////////////////// -bool ConsoleHandler::InjectHookDLL() +bool ConsoleHandler::InjectHookDLL(PROCESS_INFORMATION& pi) { // allocate memory for parameter in the remote process wstring strHookDllPath(GetModulePath(NULL) + wstring(L"\\ConsoleHook.dll")); if (::GetFileAttributes(strHookDllPath.c_str()) == INVALID_FILE_ATTRIBUTES) return false; + CONTEXT context; + + void* mem = NULL; + size_t memLen = 0; + UINT_PTR fnLoadLibrary = NULL; + + size_t codeSize; + +#ifdef _WIN64 + WOW64_CONTEXT wow64Context; + BOOL isWow64Process = FALSE; + DWORD fnWow64LoadLibrary = 0; + + ::ZeroMemory(&wow64Context, sizeof(WOW64_CONTEXT)); + ::IsWow64Process(pi.hProcess, &isWow64Process); + codeSize = isWow64Process ? 20 : 91; +#else + codeSize = 20; +#endif + + ::ZeroMemory(&context, sizeof(CONTEXT)); + + shared_array code(new BYTE[codeSize + (MAX_PATH*sizeof(wchar_t))]); + + memLen = (strHookDllPath.length()+1)*sizeof(wchar_t); + if (memLen > MAX_PATH*sizeof(wchar_t)) return false; + + ::CopyMemory(code.get() + codeSize, strHookDllPath.c_str(), memLen); + memLen += codeSize; + +#ifdef _WIN64 + + if (isWow64Process) + { + wow64Context.ContextFlags = CONTEXT_FULL; + ::Wow64GetThreadContext(pi.hThread, &wow64Context); + + mem = ::VirtualAllocEx(pi.hProcess, NULL, memLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + + // get 32-bit kernel32 + wstring strConsoleWowPath(GetModulePath(NULL) + wstring(L"\\ConsoleWow.exe")); + + STARTUPINFO si; + ::ZeroMemory(&si, sizeof(STARTUPINFO)); + + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + + PROCESS_INFORMATION pi; + DWORD dwStartupFlags = 0;//CREATE_NEW_CONSOLE|CREATE_SUSPENDED|CREATE_UNICODE_ENVIRONMENT; + + if (!::CreateProcess( + NULL, + const_cast(strConsoleWowPath.c_str()), + NULL, + NULL, + FALSE, + dwStartupFlags, + NULL, + NULL, + &si, + &pi)) + { + return false; + } + + shared_ptr wowProcess(pi.hProcess, ::CloseHandle); + shared_ptr wowThread(pi.hThread, ::CloseHandle); + + if (::WaitForSingleObject(wowProcess.get(), 5000) == WAIT_TIMEOUT) + { + return false; + } + + ::GetExitCodeProcess(wowProcess.get(), reinterpret_cast(&fnWow64LoadLibrary)); + } + else + { + context.ContextFlags = CONTEXT_FULL; + ::GetThreadContext(pi.hThread, &context); + + mem = ::VirtualAllocEx(pi.hProcess, NULL, memLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + fnLoadLibrary = (UINT_PTR)::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"); + } + + +#else + context.ContextFlags = CONTEXT_FULL; + ::GetThreadContext(pi.hThread, &context); + + mem = ::VirtualAllocEx(pi.hProcess, NULL, memLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + fnLoadLibrary = (UINT_PTR)::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"); +#endif + + union + { + PBYTE pB; + PINT pI; + PULONGLONG pL; + } ip; + + ip.pB = code.get(); + +#ifdef _WIN64 + + if (isWow64Process) + { + *ip.pB++ = 0x68; // push eip + *ip.pI++ = wow64Context.Eip; + *ip.pB++ = 0x9c; // pushf + *ip.pB++ = 0x60; // pusha + *ip.pB++ = 0x68; // push "path\to\our.dll" + *ip.pI++ = (DWORD)mem + codeSize; + *ip.pB++ = 0xe8; // call LoadLibraryW + *ip.pI++ = (DWORD)fnWow64LoadLibrary - ((DWORD)mem + (ip.pB+4 - code.get())); + *ip.pB++ = 0x61; // popa + *ip.pB++ = 0x9d; // popf + *ip.pB++ = 0xc3; // ret + + ::WriteProcessMemory(pi.hProcess, mem, code.get(), memLen, NULL); + ::FlushInstructionCache(pi.hProcess, mem, memLen); + wow64Context.Eip = (DWORD)mem; + ::Wow64SetThreadContext(pi.hThread, &wow64Context); + } + else + { + *ip.pL++ = context.Rip; + *ip.pL++ = fnLoadLibrary; + *ip.pB++ = 0x9C; // pushfq + *ip.pB++ = 0x50; // push rax + *ip.pB++ = 0x51; // push rcx + *ip.pB++ = 0x52; // push rdx + *ip.pB++ = 0x53; // push rbx + *ip.pB++ = 0x55; // push rbp + *ip.pB++ = 0x56; // push rsi + *ip.pB++ = 0x57; // push rdi + *ip.pB++ = 0x41; *ip.pB++ = 0x50; // push r8 + *ip.pB++ = 0x41; *ip.pB++ = 0x51; // push r9 + *ip.pB++ = 0x41; *ip.pB++ = 0x52; // push r10 + *ip.pB++ = 0x41; *ip.pB++ = 0x53; // push r11 + *ip.pB++ = 0x41; *ip.pB++ = 0x54; // push r12 + *ip.pB++ = 0x41; *ip.pB++ = 0x55; // push r13 + *ip.pB++ = 0x41; *ip.pB++ = 0x56; // push r14 + *ip.pB++ = 0x41; *ip.pB++ = 0x57; // push r15 + *ip.pB++ = 0x48; // sub rsp, 40 + *ip.pB++ = 0x83; + *ip.pB++ = 0xEC; + *ip.pB++ = 0x28; + + *ip.pB++ = 0x48; // lea ecx, "path\to\our.dll" + *ip.pB++ = 0x8D; + *ip.pB++ = 0x0D; + *ip.pI++ = 40; + + *ip.pB++ = 0xFF; // call LoadLibraryW + *ip.pB++ = 0x15; + *ip.pI++ = -49; + + *ip.pB++ = 0x48; // add rsp, 40 + *ip.pB++ = 0x83; + *ip.pB++ = 0xC4; + *ip.pB++ = 0x28; + + *ip.pB++ = 0x41; *ip.pB++ = 0x5F; // pop r15 + *ip.pB++ = 0x41; *ip.pB++ = 0x5E; // pop r14 + *ip.pB++ = 0x41; *ip.pB++ = 0x5D; // pop r13 + *ip.pB++ = 0x41; *ip.pB++ = 0x5C; // pop r12 + *ip.pB++ = 0x41; *ip.pB++ = 0x5B; // pop r11 + *ip.pB++ = 0x41; *ip.pB++ = 0x5A; // pop r10 + *ip.pB++ = 0x41; *ip.pB++ = 0x59; // pop r9 + *ip.pB++ = 0x41; *ip.pB++ = 0x58; // pop r8 + *ip.pB++ = 0x5F; // pop rdi + *ip.pB++ = 0x5E; // pop rsi + *ip.pB++ = 0x5D; // pop rbp + *ip.pB++ = 0x5B; // pop rbx + *ip.pB++ = 0x5A; // pop rdx + *ip.pB++ = 0x59; // pop rcx + *ip.pB++ = 0x58; // pop rax + *ip.pB++ = 0x9D; // popfq + *ip.pB++ = 0xff; // jmp Rip + *ip.pB++ = 0x25; + *ip.pI++ = -91; + + ::WriteProcessMemory(pi.hProcess, mem, code.get(), memLen, NULL); + ::FlushInstructionCache(pi.hProcess, mem, memLen); + context.Rip = (UINT_PTR)mem + 16; + ::SetThreadContext(pi.hThread, &context); + } + +#else + + *ip.pB++ = 0x68; // push eip + *ip.pI++ = context.Eip; + *ip.pB++ = 0x9c; // pushf + *ip.pB++ = 0x60; // pusha + *ip.pB++ = 0x68; // push "path\to\our.dll" + *ip.pI++ = (UINT_PTR)mem + codeSize; + *ip.pB++ = 0xe8; // call LoadLibraryW + *ip.pI++ = (UINT_PTR)fnLoadLibrary - ((UINT_PTR)mem + (ip.pB+4 - code.get())); + *ip.pB++ = 0x61; // popa + *ip.pB++ = 0x9d; // popf + *ip.pB++ = 0xc3; // ret + + ::WriteProcessMemory(pi.hProcess, mem, code.get(), memLen, NULL); + ::FlushInstructionCache(pi.hProcess, mem, memLen); + context.Eip = (UINT_PTR)mem; + ::SetThreadContext(pi.hThread, &context); +#endif + + return true; + +/* shared_ptr hRemoteThread; shared_ptr pszHookDllPathRemote( static_cast(::VirtualAllocEx( @@ -423,6 +636,7 @@ bool ConsoleHandler::InjectHookDLL() if (::WaitForSingleObject(hRemoteThread.get(), 10000) == WAIT_TIMEOUT) return false; return true; +*/ } ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index 441271c7..f1b07ea6 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -49,7 +49,7 @@ class ConsoleHandler bool CreateSharedObjects(DWORD dwConsoleProcessId); - bool InjectHookDLL(); + bool InjectHookDLL(PROCESS_INFORMATION& pi); private: diff --git a/Console2.sln b/Console2.sln index 92e8af80..c488717c 100644 --- a/Console2.sln +++ b/Console2.sln @@ -10,6 +10,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution devel_changes.txt = devel_changes.txt EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleWow", "ConsoleWow\ConsoleWow.vcproj", "{8A25E8AF-CC4A-4145-B878-3D99271562D4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -44,6 +46,12 @@ Global {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release|Win32.Build.0 = Release|Win32 {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release|x64.ActiveCfg = Release|x64 {6EA5C354-A242-49F3-88D1-559EACA7FB8A}.Release|x64.Build.0 = Release|x64 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Debug|Win32.Build.0 = Debug|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Debug|x64.ActiveCfg = Debug|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Release|Win32.ActiveCfg = Release|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Release|Win32.Build.0 = Release|Win32 + {8A25E8AF-CC4A-4145-B878-3D99271562D4}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ConsoleHook/ConsoleHook.vcproj b/ConsoleHook/ConsoleHook.vcproj index 44470360..7389456e 100644 --- a/ConsoleHook/ConsoleHook.vcproj +++ b/ConsoleHook/ConsoleHook.vcproj @@ -125,7 +125,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ConsoleWow/ReadMe.txt b/ConsoleWow/ReadMe.txt new file mode 100644 index 00000000..b5848d97 --- /dev/null +++ b/ConsoleWow/ReadMe.txt @@ -0,0 +1,33 @@ +======================================================================== + CONSOLE APPLICATION : ConsoleWow Project Overview +======================================================================== + +AppWizard has created this ConsoleWow application for you. + +This file contains a summary of what you will find in each of the files that +make up your ConsoleWow application. + + +ConsoleWow.vcproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +ConsoleWow.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named ConsoleWow.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/ConsoleWow/stdafx.cpp b/ConsoleWow/stdafx.cpp new file mode 100644 index 00000000..c2882416 --- /dev/null +++ b/ConsoleWow/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ConsoleWow.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/ConsoleWow/stdafx.h b/ConsoleWow/stdafx.h new file mode 100644 index 00000000..b700aa29 --- /dev/null +++ b/ConsoleWow/stdafx.h @@ -0,0 +1,12 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include + +#include diff --git a/ConsoleWow/targetver.h b/ConsoleWow/targetver.h new file mode 100644 index 00000000..6fe8eb79 --- /dev/null +++ b/ConsoleWow/targetver.h @@ -0,0 +1,13 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + From ef6edcf827dcca4bdf60b9d349c2f242ddee361d Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Thu, 2 Sep 2010 23:12:47 +0100 Subject: [PATCH 025/207] 64-bit Console -> 32-bit shell injection --- Console/ConsoleHandler.cpp | 36 ++++++++++++++++++++++----------- Console/ConsoleHandler.h | 4 ++-- Console/ConsoleView.cpp | 4 ++-- ConsoleHook/ConsoleHandler.cpp | 4 ++-- ConsoleHook/ConsoleHandler.h | 2 +- ConsoleHook/ConsoleHook.vcproj | 2 ++ ConsoleWow/ConsoleWow.vcproj | 2 ++ devel_changes.txt | 23 +++++++++++++++++++++ shared/Structures.h | 37 +++++++++++++++++++++++++++++++++- 9 files changed, 94 insertions(+), 20 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index f3b76fff..15f9a846 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -372,8 +372,9 @@ bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId) bool ConsoleHandler::InjectHookDLL(PROCESS_INFORMATION& pi) { + // allocate memory for parameter in the remote process - wstring strHookDllPath(GetModulePath(NULL) + wstring(L"\\ConsoleHook.dll")); + wstring strHookDllPath(GetModulePath(NULL)); if (::GetFileAttributes(strHookDllPath.c_str()) == INVALID_FILE_ATTRIBUTES) return false; @@ -384,10 +385,10 @@ bool ConsoleHandler::InjectHookDLL(PROCESS_INFORMATION& pi) UINT_PTR fnLoadLibrary = NULL; size_t codeSize; + BOOL isWow64Process = FALSE; #ifdef _WIN64 WOW64_CONTEXT wow64Context; - BOOL isWow64Process = FALSE; DWORD fnWow64LoadLibrary = 0; ::ZeroMemory(&wow64Context, sizeof(WOW64_CONTEXT)); @@ -397,6 +398,17 @@ bool ConsoleHandler::InjectHookDLL(PROCESS_INFORMATION& pi) codeSize = 20; #endif + if (isWow64Process) + { + // starting a 32-bit process from a 64-bit console + strHookDllPath += wstring(L"\\ConsoleHook32.dll"); + } + else + { + // same bitness :-) + strHookDllPath += wstring(L"\\ConsoleHook.dll"); + } + ::ZeroMemory(&context, sizeof(CONTEXT)); shared_array code(new BYTE[codeSize + (MAX_PATH*sizeof(wchar_t))]); @@ -419,14 +431,14 @@ bool ConsoleHandler::InjectHookDLL(PROCESS_INFORMATION& pi) // get 32-bit kernel32 wstring strConsoleWowPath(GetModulePath(NULL) + wstring(L"\\ConsoleWow.exe")); - STARTUPINFO si; - ::ZeroMemory(&si, sizeof(STARTUPINFO)); + STARTUPINFO siWow; + ::ZeroMemory(&siWow, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; + siWow.cb = sizeof(STARTUPINFO); + siWow.dwFlags = STARTF_USESHOWWINDOW; + siWow.wShowWindow = SW_HIDE; - PROCESS_INFORMATION pi; + PROCESS_INFORMATION piWow; DWORD dwStartupFlags = 0;//CREATE_NEW_CONSOLE|CREATE_SUSPENDED|CREATE_UNICODE_ENVIRONMENT; if (!::CreateProcess( @@ -438,14 +450,14 @@ bool ConsoleHandler::InjectHookDLL(PROCESS_INFORMATION& pi) dwStartupFlags, NULL, NULL, - &si, - &pi)) + &siWow, + &piWow)) { return false; } - shared_ptr wowProcess(pi.hProcess, ::CloseHandle); - shared_ptr wowThread(pi.hThread, ::CloseHandle); + shared_ptr wowProcess(piWow.hProcess, ::CloseHandle); + shared_ptr wowThread(piWow.hThread, ::CloseHandle); if (::WaitForSingleObject(wowProcess.get(), 5000) == WAIT_TIMEOUT) { diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index f1b07ea6..e25adff1 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -34,7 +34,7 @@ class ConsoleHandler SharedMemory& GetCursorInfo() { return m_cursorInfo; } SharedMemory& GetConsoleBuffer() { return m_consoleBuffer; } SharedMemory& GetCopyInfo() { return m_consoleCopyInfo; } - SharedMemory& GetTextInfo() { return m_consoleTextInfo; } + SharedMemory& GetTextInfo() { return m_consoleTextInfo; } SharedMemory& GetNewConsoleSize() { return m_newConsoleSize; } SharedMemory& GetNewScrollPos() { return m_newScrollPos; } @@ -74,7 +74,7 @@ class ConsoleHandler SharedMemory m_cursorInfo; SharedMemory m_consoleBuffer; SharedMemory m_consoleCopyInfo; - SharedMemory m_consoleTextInfo; + SharedMemory m_consoleTextInfo; SharedMemory m_consoleMouseEvent; SharedMemory m_newConsoleSize; diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 9d34d07e..dab782f5 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -2025,7 +2025,7 @@ void ConsoleView::SendTextToConsole(const wchar_t* pszText) if (textLen == 0) return; - SharedMemory& textInfo = m_consoleHandler.GetTextInfo(); + SharedMemory& textInfo = m_consoleHandler.GetTextInfo(); { SharedMemoryLock memLock(textInfo); @@ -2050,7 +2050,7 @@ void ConsoleView::SendTextToConsole(const wchar_t* pszText) return; } - textInfo = reinterpret_cast(pRemoteMemory); + textInfo->mem = reinterpret_cast(pRemoteMemory); textInfo.SetReqEvent(); } diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index bd9ecc43..ee131286 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -851,10 +851,10 @@ DWORD ConsoleHandler::MonitorThread() shared_ptr textBuffer; - if (*m_consoleTextInfo.Get() != NULL) + if (m_consoleTextInfo->mem != NULL) { textBuffer.reset( - reinterpret_cast(*m_consoleTextInfo.Get()), + reinterpret_cast(m_consoleTextInfo->mem), bind(::VirtualFreeEx, ::GetCurrentProcess(), _1, NULL, MEM_RELEASE)); } diff --git a/ConsoleHook/ConsoleHandler.h b/ConsoleHook/ConsoleHandler.h index 0e87e756..fe83b991 100644 --- a/ConsoleHook/ConsoleHandler.h +++ b/ConsoleHook/ConsoleHandler.h @@ -55,7 +55,7 @@ class ConsoleHandler SharedMemory m_cursorInfo; SharedMemory m_consoleBuffer; SharedMemory m_consoleCopyInfo; - SharedMemory m_consoleTextInfo; + SharedMemory m_consoleTextInfo; SharedMemory m_consoleMouseEvent; SharedMemory m_newConsoleSize; diff --git a/ConsoleHook/ConsoleHook.vcproj b/ConsoleHook/ConsoleHook.vcproj index 7389456e..feabbd9b 100644 --- a/ConsoleHook/ConsoleHook.vcproj +++ b/ConsoleHook/ConsoleHook.vcproj @@ -96,6 +96,7 @@ /> diff --git a/devel_changes.txt b/devel_changes.txt index 09980544..f26c0abf 100644 --- a/devel_changes.txt +++ b/devel_changes.txt @@ -1,6 +1,29 @@ v2.00 ===== +Build 147 +========= + +- fixed keyboard switching for Vista/Win7 + +- fixed visible scrollbars on startup with 'Show scrollbars' option turned off + +- added support for flat scrollbars + +- added icons in the File->New Tab menu (thanks to chrisz for the patch) + +- added an option for using a default program icon in the tab menu + +- fixed exit codes + +- new inject code (many thanks to Jason Hood, creator of AnsiCon http://adoxa.110mb.com/ansicon + for the code) The new injection code enables running 32-bit shells from 64-bit Console, + starting .NET console applications (e.g. powershell) directly, it doesn't use CreateRemoteThread, + so Windows patches and antivirus software that disables the call should not cause problems. The + code still hasn't been tested with Vista/Win7 UAC, but it does work for shell processes started + as another user, so we'll have that feature in Console soon as well. + + Build 146 ========= diff --git a/shared/Structures.h b/shared/Structures.h index 356b3c88..0b3ea884 100644 --- a/shared/Structures.h +++ b/shared/Structures.h @@ -49,7 +49,13 @@ struct ConsoleParams // stuff set by console hook DWORD dwMaxRows; DWORD dwMaxColumns; - HWND hwndConsoleWindow; + union + { + HWND hwndConsoleWindow; + // padding for 32-bit processes started from 64-bit Console + __int64 padding; + }; + DWORD dwHookThreadId; }; @@ -145,6 +151,11 @@ struct ConsoleInfo ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// struct CharInfo @@ -165,3 +176,27 @@ struct CharInfo ////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +struct TextInfo +{ + TextInfo() + : padding(0) + { + } + + union + { + UINT_PTR mem; + // padding for 32-bit processes started from 64-bit Console + __int64 padding; + }; +}; + +////////////////////////////////////////////////////////////////////////////// From b55c83a859339e6f98cd9328b29f00e22195c133 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Tue, 7 Sep 2010 12:22:21 +0200 Subject: [PATCH 026/207] Code cleanup --- Console/ConsoleHandler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 15f9a846..f8b41d67 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -439,7 +439,6 @@ bool ConsoleHandler::InjectHookDLL(PROCESS_INFORMATION& pi) siWow.wShowWindow = SW_HIDE; PROCESS_INFORMATION piWow; - DWORD dwStartupFlags = 0;//CREATE_NEW_CONSOLE|CREATE_SUSPENDED|CREATE_UNICODE_ENVIRONMENT; if (!::CreateProcess( NULL, @@ -447,7 +446,7 @@ bool ConsoleHandler::InjectHookDLL(PROCESS_INFORMATION& pi) NULL, NULL, FALSE, - dwStartupFlags, + 0, NULL, NULL, &siWow, From b908e692bfd4b134fcdd95220f213c479fd7b1a7 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Tue, 7 Sep 2010 12:23:34 +0200 Subject: [PATCH 027/207] Code cleanup --- Console/ConsoleHandler.cpp | 49 -------------------------------------- 1 file changed, 49 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index f8b41d67..eb3c1b26 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -599,55 +599,6 @@ bool ConsoleHandler::InjectHookDLL(PROCESS_INFORMATION& pi) #endif return true; - -/* - shared_ptr hRemoteThread; - shared_ptr pszHookDllPathRemote( - static_cast(::VirtualAllocEx( - m_hConsoleProcess.get(), - NULL, - strHookDllPath.length()*sizeof(wchar_t), - MEM_COMMIT, - PAGE_READWRITE)), - bind(::VirtualFreeEx, m_hConsoleProcess.get(), _1, NULL, MEM_RELEASE)); - - if (!pszHookDllPathRemote) return false; - - // write the memory - if (!::WriteProcessMemory( - m_hConsoleProcess.get(), - (PVOID)pszHookDllPathRemote.get(), - (PVOID)strHookDllPath.c_str(), - strHookDllPath.length()*sizeof(wchar_t), - NULL)) - { - return false; - } - - // get address to LoadLibraryW function - PTHREAD_START_ROUTINE pfnThreadRoutine = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(L"Kernel32.dll"), "LoadLibraryW"); - if (pfnThreadRoutine == NULL) return false; - - // start the remote thread - hRemoteThread = shared_ptr( - ::CreateRemoteThread( - m_hConsoleProcess.get(), - NULL, - 0, - pfnThreadRoutine, - (PVOID)pszHookDllPathRemote.get(), - 0, - NULL), - ::CloseHandle); - - if (!hRemoteThread) return false; - - // wait for the thread to finish -// ::WaitForSingleObject(hRemoteThread.get(), INFINITE); - if (::WaitForSingleObject(hRemoteThread.get(), 10000) == WAIT_TIMEOUT) return false; - - return true; -*/ } ////////////////////////////////////////////////////////////////////////////// From 7c299f1a4b510eb276a12d5b07e4ac9f60c12ae3 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Tue, 7 Sep 2010 12:26:39 +0200 Subject: [PATCH 028/207] Returned ConsoleWow project --- Console2.sln | 1 - 1 file changed, 1 deletion(-) diff --git a/Console2.sln b/Console2.sln index c488717c..55c73140 100644 --- a/Console2.sln +++ b/Console2.sln @@ -7,7 +7,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DA1A8A1D-90C0-49B9-A9B2-DF2C574F19E6}" ProjectSection(SolutionItems) = preProject setup\console.iss = setup\console.iss - devel_changes.txt = devel_changes.txt EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleWow", "ConsoleWow\ConsoleWow.vcproj", "{8A25E8AF-CC4A-4145-B878-3D99271562D4}" From 550ae38068b61c609d29d20ac3947c3c6f67c8ac Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Wed, 8 Sep 2010 18:03:02 +0200 Subject: [PATCH 029/207] Returned devel_changes.txt to the solution --- Console2.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/Console2.sln b/Console2.sln index 55c73140..c488717c 100644 --- a/Console2.sln +++ b/Console2.sln @@ -7,6 +7,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DA1A8A1D-90C0-49B9-A9B2-DF2C574F19E6}" ProjectSection(SolutionItems) = preProject setup\console.iss = setup\console.iss + devel_changes.txt = devel_changes.txt EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleWow", "ConsoleWow\ConsoleWow.vcproj", "{8A25E8AF-CC4A-4145-B878-3D99271562D4}" From 10f7da2dd838323a77dd9d9937bf0e181174f5ab Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Wed, 8 Sep 2010 19:57:51 +0200 Subject: [PATCH 030/207] Help update --- help/html/acknowledgements.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/help/html/acknowledgements.html b/help/html/acknowledgements.html index 882f5419..c1b29366 100644 --- a/help/html/acknowledgements.html +++ b/help/html/acknowledgements.html @@ -31,6 +31,8 @@

Acknowledgements

  • jachymko for several code patches and suggestions
  • Anduin Withers for fixed-pitch font dialog patch
  • +
  • Kirill for many patches and bug fixes
  • +
  • Jason Hood, creator of AnsiCon for the new inject code

Thanks also goes to all the people using and testing Console, From 7a8b7662c2577f2bbeaba93b70626b5b13282db5 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Thu, 9 Sep 2010 17:32:45 +0100 Subject: [PATCH 031/207] A quick hack for testing --- Console/Console.rc | 44 +++++++++++-------- Console/ConsoleHandler.cpp | 83 +++++++++++++++++++++++++++++++---- Console/ConsoleHandler.h | 13 +++++- Console/ConsoleView.cpp | 4 ++ Console/Helpers.cpp | 15 +++++++ Console/Helpers.h | 1 + Console/PageSettingsTabs1.cpp | 3 ++ Console/PageSettingsTabs1.h | 2 + Console/SettingsHandler.cpp | 2 + Console/SettingsHandler.h | 2 + Console/resource.h | 9 ++-- 11 files changed, 145 insertions(+), 33 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index e5a8277c..a2a3ff36 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -476,25 +476,27 @@ STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "&Title:",-1,8,19,17,8,0,WS_EX_TRANSPARENT - EDITTEXT IDC_TAB_TITLE,28,16,94,14,ES_AUTOHSCROLL - LTEXT "Icon:",-1,8,34,18,8 + LTEXT "&Title:",IDC_STATIC,8,19,17,8,0,WS_EX_TRANSPARENT + EDITTEXT IDC_TAB_TITLE,28,16,105,14,ES_AUTOHSCROLL + LTEXT "Icon:",IDC_STATIC,8,34,18,8 EDITTEXT IDC_TAB_ICON,28,31,105,14,ES_AUTOHSCROLL PUSHBUTTON "...",IDC_BTN_BROWSE_ICON,136,31,15,14 CONTROL "Use default",IDC_CHECK_DEFAULT_ICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,33,53,10 - LTEXT "S&hell:",-1,7,71,23,8 - EDITTEXT IDC_TAB_SHELL,46,68,145,14,ES_AUTOHSCROLL + LTEXT "S&hell:",IDC_STATIC,7,71,23,8 + EDITTEXT IDC_TAB_SHELL,51,68,139,14,ES_AUTOHSCROLL PUSHBUTTON "...",IDC_BTN_BROWSE_SHELL,193,68,15,14 - LTEXT "Startup &dir:",-1,7,86,38,8 - EDITTEXT IDC_TAB_INIT_DIR,46,83,145,14,ES_AUTOHSCROLL + LTEXT "Startup &dir:",IDC_STATIC,7,86,38,8 + EDITTEXT IDC_TAB_INIT_DIR,51,83,139,14,ES_AUTOHSCROLL PUSHBUTTON "...",IDC_BTN_BROWSE_DIR,193,83,15,14 - GROUPBOX "Shell",-1,0,55,217,49,WS_GROUP,WS_EX_TRANSPARENT - LTEXT "Style:",-1,5,123,20,8 - COMBOBOX IDC_COMBO_CURSOR,28,121,82,83,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Col&or:",-1,5,141,20,8 - CONTROL "",IDC_CURSOR_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,28,138,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Cursor",-1,0,107,120,53,0,WS_EX_TRANSPARENT - GROUPBOX "Title && icon",-1,0,3,217,50,0,WS_EX_TRANSPARENT + LTEXT "Run as user:",IDC_STATIC,7,101,42,8 + EDITTEXT IDC_TAB_USER,51,98,82,14,ES_AUTOHSCROLL + GROUPBOX "Shell",IDC_STATIC,0,55,217,63,WS_GROUP,WS_EX_TRANSPARENT + LTEXT "Style:",IDC_STATIC,5,136,20,8 + COMBOBOX IDC_COMBO_CURSOR,28,134,82,83,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Col&or:",IDC_STATIC,118,136,20,8 + CONTROL "",IDC_CURSOR_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,140,133,16,14,WS_EX_DLGMODALFRAME + GROUPBOX "Cursor",IDC_STATIC,0,120,194,37,0,WS_EX_TRANSPARENT + GROUPBOX "Title && icon",IDC_STATIC,0,3,217,50,0,WS_EX_TRANSPARENT END IDD_SETTINGS_TABS_2 DIALOGEX 0, 0, 223, 172 @@ -639,13 +641,17 @@ BEGIN IDD_SETTINGS_TABS_1, DIALOG BEGIN + VERTGUIDE, 51 + VERTGUIDE, 133 + VERTGUIDE, 190 VERTGUIDE, 217 - HORZGUIDE, 20 + HORZGUIDE, 23 HORZGUIDE, 38 - HORZGUIDE, 72 - HORZGUIDE, 87 - HORZGUIDE, 124 - HORZGUIDE, 142 + HORZGUIDE, 75 + HORZGUIDE, 90 + HORZGUIDE, 105 + HORZGUIDE, 120 + HORZGUIDE, 140 END IDD_SETTINGS_TABS_2, DIALOG diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index eb3c1b26..4c10b6e5 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -72,8 +72,51 @@ void ConsoleHandler::SetupDelegates(ConsoleChangeDelegate consoleChangeDelegate, ////////////////////////////////////////////////////////////////////////////// -bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstring& strInitialDir, const wstring& strInitialCmd, const wstring& strConsoleTitle, DWORD dwStartupRows, DWORD dwStartupColumns, bool bDebugFlag) +bool ConsoleHandler::StartShellProcess +( + const wstring& strCustomShell, + const wstring& strInitialDir, + const wstring& strUser, + const wstring& strPassword, + const wstring& strInitialCmd, + const wstring& strConsoleTitle, + DWORD dwStartupRows, + DWORD dwStartupColumns, + bool bDebugFlag +) { + + wstring strUsername(strUser); + wstring strDomain; + + shared_ptr userToken; + shared_ptr userEnvironment; + + if (strUsername.length() > 0) + { + size_t pos = strUsername.find(L'\\'); + if (pos != wstring::npos) + { + strDomain = strUsername.substr(0, pos); + strUsername = strUsername.substr(pos+1); + } + + HANDLE hUserToken = NULL; + ::LogonUser( + strUsername.c_str(), + strDomain.length() > 0 ? strDomain.c_str() : NULL, + strPassword.c_str(), + LOGON32_LOGON_INTERACTIVE, + LOGON32_PROVIDER_DEFAULT, + &hUserToken); + + userToken.reset(hUserToken, ::CloseHandle); + + void* pEnvironment = NULL; + ::CreateEnvironmentBlock(&pEnvironment, userToken.get(), FALSE); + userEnvironment.reset(pEnvironment, ::DestroyEnvironmentBlock); + } + wstring strShellCmdLine(strCustomShell); if (strShellCmdLine.length() == 0) @@ -106,7 +149,7 @@ bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstr // strStartupTitle = str(wformat(L"Console2 command window 0x%08X") % this); } - wstring strStartupDir(Helpers::ExpandEnvironmentStrings(strInitialDir)); + wstring strStartupDir((strUsername.length() > 0) ? Helpers::ExpandEnvironmentStringsForUser(userToken, strInitialDir) : Helpers::ExpandEnvironmentStrings(strInitialDir)); if (strStartupDir.length() > 0) { @@ -169,19 +212,41 @@ bool ConsoleHandler::StartShellProcess(const wstring& strCustomShell, const wstr // TODO: not supported yet //if (bDebugFlag) dwStartupFlags |= DEBUG_PROCESS; - if (!::CreateProcess( - NULL, - const_cast(Helpers::ExpandEnvironmentStrings(strShellCmdLine).c_str()), - NULL, + + if (strUsername.length() > 0) + { + if (!::CreateProcessWithLogonW( + strUsername.c_str(), + strDomain.length() > 0 ? strDomain.c_str() : NULL, + strPassword.c_str(), + LOGON_WITH_PROFILE, NULL, - FALSE, + const_cast(Helpers::ExpandEnvironmentStringsForUser(userToken, strShellCmdLine).c_str()), dwStartupFlags, - s_environmentBlock.get(), + userEnvironment.get(), (strStartupDir.length() > 0) ? const_cast(strStartupDir.c_str()) : NULL, &si, &pi)) + { + return false; + } + } + else { - return false; + if (!::CreateProcess( + NULL, + const_cast(Helpers::ExpandEnvironmentStrings(strShellCmdLine).c_str()), + NULL, + NULL, + FALSE, + dwStartupFlags, + s_environmentBlock.get(), + (strStartupDir.length() > 0) ? const_cast(strStartupDir.c_str()) : NULL, + &si, + &pi)) + { + return false; + } } // create shared memory objects diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index e25adff1..f860c3f5 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -22,7 +22,18 @@ class ConsoleHandler public: void SetupDelegates(ConsoleChangeDelegate consoleChangeDelegate, ConsoleCloseDelegate consoleCloseDelegate); - bool StartShellProcess(const wstring& strCustomShell, const wstring& strInitialDir, const wstring& strInitialCmd, const wstring& strConsoleTitle, DWORD dwStartupRows, DWORD dwStartupColumns, bool bDebugFlag); + bool StartShellProcess + ( + const wstring& strCustomShell, + const wstring& strInitialDir, + const wstring& strUser, + const wstring& strPassword, + const wstring& strInitialCmd, + const wstring& strConsoleTitle, + DWORD dwStartupRows, + DWORD dwStartupColumns, + bool bDebugFlag + ); DWORD StartMonitorThread(); void StopMonitorThread(); diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index dab782f5..ca512dcb 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -158,9 +158,13 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam* strShell = m_tabData->strShell; } + wstring strPassword(m_tabData->strUser.length() > 0 ? L"games" : L""); + if (!m_consoleHandler.StartShellProcess( strShell, strInitialDir, + m_tabData->strUser, + strPassword, m_strInitialCmd, g_settingsHandler->GetAppearanceSettings().windowSettings.bUseConsoleTitle ? m_tabData->strTitle : wstring(L""), m_dwStartupRows, diff --git a/Console/Helpers.cpp b/Console/Helpers.cpp index bc677b2d..3fa3c752 100644 --- a/Console/Helpers.cpp +++ b/Console/Helpers.cpp @@ -41,6 +41,21 @@ wstring Helpers::ExpandEnvironmentStrings(const wstring& str) ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +wstring Helpers::ExpandEnvironmentStringsForUser(const shared_ptr& userToken, const wstring& str) +{ + shared_array szExpanded(new wchar_t[0x8000]); + + ::ZeroMemory(szExpanded.get(), 0x8000*sizeof(wchar_t)); + ::ExpandEnvironmentStringsForUser(userToken.get(), str.c_str(), szExpanded.get(), 0x8000); + + return wstring(szExpanded.get()); +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// void Helpers::GetMonitorRect(HWND hWnd, CRect& rectMonitor) diff --git a/Console/Helpers.h b/Console/Helpers.h index 90b329ca..7409956c 100644 --- a/Console/Helpers.h +++ b/Console/Helpers.h @@ -17,6 +17,7 @@ class Helpers static wstring GetModulePath(HINSTANCE hInstance); static wstring ExpandEnvironmentStrings(const wstring& str); + static wstring ExpandEnvironmentStringsForUser(const shared_ptr& userToken, const wstring& str); static void GetMonitorRect(HWND hWnd, CRect& rectMonitor); static void GetDesktopRect(HWND hWnd, CRect& rectDesktop); diff --git a/Console/PageSettingsTabs1.cpp b/Console/PageSettingsTabs1.cpp index 14a65cc4..0d55e994 100644 --- a/Console/PageSettingsTabs1.cpp +++ b/Console/PageSettingsTabs1.cpp @@ -21,6 +21,7 @@ PageSettingsTabs1::PageSettingsTabs1() , m_nUseDefaultIcon(0) , m_strShell(L"") , m_strInitialDir(L"") +, m_strUser(L"") { } @@ -237,6 +238,7 @@ void PageSettingsTabs1::Load(shared_ptr& tabData) m_strShell = m_tabData->strShell.c_str(); m_strInitialDir = m_tabData->strInitialDir.c_str(); + m_strUser = m_tabData->strUser.c_str(); m_comboCursor.SetCurSel(m_tabData->dwCursorStyle); @@ -262,6 +264,7 @@ void PageSettingsTabs1::Save() m_tabData->strShell = m_strShell; m_tabData->strInitialDir = m_strInitialDir; + m_tabData->strUser = m_strUser; m_tabData->dwCursorStyle = m_comboCursor.GetCurSel(); } diff --git a/Console/PageSettingsTabs1.h b/Console/PageSettingsTabs1.h index 5ed4ff6e..ebb10f54 100644 --- a/Console/PageSettingsTabs1.h +++ b/Console/PageSettingsTabs1.h @@ -29,6 +29,7 @@ class PageSettingsTabs1 DDX_CHECK(IDC_CHECK_DEFAULT_ICON, m_nUseDefaultIcon) DDX_TEXT(IDC_TAB_SHELL, m_strShell) DDX_TEXT(IDC_TAB_INIT_DIR, m_strInitialDir) + DDX_TEXT(IDC_TAB_USER, m_strUser) END_DDX_MAP() BEGIN_MSG_MAP(PageSettingsTabs1) @@ -84,6 +85,7 @@ class PageSettingsTabs1 CString m_strShell; CString m_strInitialDir; + CString m_strUser; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index 65c165b6..3f4ae113 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -1504,6 +1504,7 @@ bool TabSettings::Load(const CComPtr& pSettingsRoot) { XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"shell"), tabData->strShell, strDefaultShell); XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"init_dir"), tabData->strInitialDir, strDefaultInitialDir); + XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"user"), tabData->strUser, L""); } if (SUCCEEDED(XmlHelper::GetDomElement(pTabElement, CComBSTR(L"cursor"), pCursorElement))) @@ -1618,6 +1619,7 @@ bool TabSettings::Save(const CComPtr& pSettingsRoot) XmlHelper::SetAttribute(pNewConsoleElement, CComBSTR(L"shell"), (*itTab)->strShell); XmlHelper::SetAttribute(pNewConsoleElement, CComBSTR(L"init_dir"), (*itTab)->strInitialDir); + XmlHelper::SetAttribute(pNewConsoleElement, CComBSTR(L"user"), (*itTab)->strUser); SettingsBase::AddTextNode(pSettingsDoc, pNewTabElement, CComBSTR(L"\n\t\t\t")); pNewTabElement->appendChild(pNewConsoleElement, &pNewConsoleOut); diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index 4db72077..718a81ad 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -583,6 +583,7 @@ struct TabData , bUseDefaultIcon(false) , strShell(shell) , strInitialDir(initialDir) + , strUser() , dwCursorStyle(0) , crCursorColor(RGB(255, 255, 255)) , backgroundImageType(bktypeNone) @@ -599,6 +600,7 @@ struct TabData wstring strShell; wstring strInitialDir; + wstring strUser; DWORD dwCursorStyle; COLORREF crCursorColor; diff --git a/Console/resource.h b/Console/resource.h index 989d8047..9865e5ee 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -215,13 +215,14 @@ #define IDC_CHECK_START_HIDDEN 1171 #define IDC_CHECK_DEFAULT_ICON 1172 #define IDC_CHECK_TABS_ON_BOTTOM 1173 -#define IDC_APPTEXT 1174 -#define IDC_APPICON 1175 -#define ID_RENAME_TAB_OK 1176 +#define IDC_TAB_USER 1174 +#define IDC_APPTEXT 1175 +#define IDC_APPICON 1176 #define ID_NEW_TAB_1 2000 #define ID_SWITCH_TAB_1 2100 #define ID_NEXT_TAB 2200 #define ID_PREV_TAB 2201 +#define ID_RENAME_TAB_OK 2202 #define IDC_DUMP_BUFFER 3000 #define ID_FILE_NEW_TAB 32775 #define ID_VIEW_CONSOLE 32777 @@ -241,7 +242,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 222 +#define _APS_NEXT_RESOURCE_VALUE 215 #define _APS_NEXT_COMMAND_VALUE 32794 #define _APS_NEXT_CONTROL_VALUE 1177 #define _APS_NEXT_SYMED_VALUE 101 From d221abc71f0402143dfeba2082b14b25ef829af5 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Tue, 14 Sep 2010 21:04:30 +0100 Subject: [PATCH 032/207] Working on user credentials --- Console/Console.rc | 41 +++++ Console/Console.vcproj | 12 ++ Console/ConsoleException.h | 16 ++ Console/ConsoleHandler.cpp | 60 ++++--- Console/ConsoleHandler.h | 2 +- Console/ConsoleView.cpp | 29 ++-- Console/DlgCredentials.cpp | 69 ++++++++ Console/DlgCredentials.h | 55 +++++++ Console/MainFrame.cpp | 2 +- Console/resource.h | 12 +- ConsoleHook/ConsoleHandler.cpp | 6 +- shared/SharedMemory.h | 292 +++++++++++++++++++++++++++++++-- 12 files changed, 537 insertions(+), 59 deletions(-) create mode 100644 Console/ConsoleException.h create mode 100644 Console/DlgCredentials.cpp create mode 100644 Console/DlgCredentials.h diff --git a/Console/Console.rc b/Console/Console.rc index a2a3ff36..d172c3e5 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -34,6 +34,47 @@ END #endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CREDENTIALS DIALOGEX 0, 0, 207, 79 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter username and password" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "&Username:",IDC_STATIC,7,16,36,8 + EDITTEXT IDC_USER,54,13,146,14,ES_AUTOHSCROLL + LTEXT "&Password:",IDC_STATIC,7,31,34,8 + EDITTEXT IDC_PASSWORD,54,28,146,14,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,93,58,50,14 + PUSHBUTTON "Cancel",IDCANCEL,150,58,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CREDENTIALS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 200 + VERTGUIDE, 54 + TOPMARGIN, 7 + BOTTOMMARGIN, 72 + HORZGUIDE, 20 + HORZGUIDE, 35 + END +END +#endif // APSTUDIO_INVOKED + #endif // Croatian resources ///////////////////////////////////////////////////////////////////////////// diff --git a/Console/Console.vcproj b/Console/Console.vcproj index c205ccfa..316dd38b 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -590,6 +590,10 @@ RelativePath=".\Cursors.cpp" > + + @@ -731,6 +735,10 @@ RelativePath=".\Console.h" > + + @@ -743,6 +751,10 @@ RelativePath=".\Cursors.h" > + + diff --git a/Console/ConsoleException.h b/Console/ConsoleException.h new file mode 100644 index 00000000..e566ee35 --- /dev/null +++ b/Console/ConsoleException.h @@ -0,0 +1,16 @@ +#pragma once + +class ConsoleException +{ + public: + ConsoleException(const wstring& message) + : m_message(message) + { + } + + const wstring& GetMessage() const { return m_message; } + + private: + + wstring m_message; +}; diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 4c10b6e5..f9968dde 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -3,6 +3,7 @@ #include "Console.h" #include "../shared/SharedMemNames.h" +#include "ConsoleException.h" #include "ConsoleHandler.h" ////////////////////////////////////////////////////////////////////////////// @@ -85,7 +86,6 @@ bool ConsoleHandler::StartShellProcess bool bDebugFlag ) { - wstring strUsername(strUser); wstring strDomain; @@ -117,6 +117,7 @@ bool ConsoleHandler::StartShellProcess userEnvironment.reset(pEnvironment, ::DestroyEnvironmentBlock); } + wstring strShellCmdLine(strCustomShell); if (strShellCmdLine.length() == 0) @@ -216,19 +217,32 @@ bool ConsoleHandler::StartShellProcess if (strUsername.length() > 0) { if (!::CreateProcessWithLogonW( - strUsername.c_str(), - strDomain.length() > 0 ? strDomain.c_str() : NULL, - strPassword.c_str(), + L"games", + NULL, + L"games", LOGON_WITH_PROFILE, NULL, - const_cast(Helpers::ExpandEnvironmentStringsForUser(userToken, strShellCmdLine).c_str()), + L"cmd.exe", dwStartupFlags, - userEnvironment.get(), - (strStartupDir.length() > 0) ? const_cast(strStartupDir.c_str()) : NULL, + NULL, + NULL, &si, &pi)) + //if (!::CreateProcessWithLogonW( + // strUsername.c_str(), + // strDomain.length() > 0 ? strDomain.c_str() : NULL, + // strPassword.c_str(), + // LOGON_WITH_PROFILE, + // NULL, + // const_cast(Helpers::ExpandEnvironmentStringsForUser(userToken, strShellCmdLine).c_str()), + // dwStartupFlags, + // userEnvironment.get(), + // (strStartupDir.length() > 0) ? const_cast(strStartupDir.c_str()) : NULL, + // &si, + // &pi)) { - return false; + throw ConsoleException(str(wformat(L"Unable to start a shell as user %1%!") % strUser)); + //return false; } } else @@ -250,7 +264,7 @@ bool ConsoleHandler::StartShellProcess } // create shared memory objects - CreateSharedObjects(pi.dwProcessId); + CreateSharedObjects(pi.dwProcessId, strUser); // write startup params m_consoleParams->dwConsoleMainThreadId = pi.dwThreadId; @@ -387,19 +401,19 @@ void ConsoleHandler::UpdateEnvironmentBlock() ////////////////////////////////////////////////////////////////////////////// -bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId) +bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId, const wstring& strUser) { // create startup params shared memory - m_consoleParams.Create((SharedMemNames::formatConsoleParams % dwConsoleProcessId).str(), 1, syncObjRequest); + m_consoleParams.Create((SharedMemNames::formatConsoleParams % dwConsoleProcessId).str(), 1, syncObjBoth, strUser); // create console info shared memory - m_consoleInfo.Create((SharedMemNames::formatInfo % dwConsoleProcessId).str(), 1, syncObjRequest); + m_consoleInfo.Create((SharedMemNames::formatInfo % dwConsoleProcessId).str(), 1, syncObjRequest, strUser); // create console info shared memory - m_cursorInfo.Create((SharedMemNames::formatCursorInfo % dwConsoleProcessId).str(), 1, syncObjRequest); + m_cursorInfo.Create((SharedMemNames::formatCursorInfo % dwConsoleProcessId).str(), 1, syncObjRequest, strUser); // TODO: max console size - m_consoleBuffer.Create((SharedMemNames::formatBuffer % dwConsoleProcessId).str(), 200*200, syncObjRequest); + m_consoleBuffer.Create((SharedMemNames::formatBuffer % dwConsoleProcessId).str(), 200*200, syncObjRequest, strUser); // initialize buffer with spaces CHAR_INFO ci; @@ -408,25 +422,24 @@ bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId) for (int i = 0; i < 200*200; ++i) ::CopyMemory(&m_consoleBuffer[i], &ci, sizeof(CHAR_INFO)); // copy info - m_consoleCopyInfo.Create((SharedMemNames::formatCopyInfo % dwConsoleProcessId).str(), 1, syncObjBoth); + m_consoleCopyInfo.Create((SharedMemNames::formatCopyInfo % dwConsoleProcessId).str(), 1, syncObjBoth, strUser); // text info (used for sending text to console) - m_consoleTextInfo.Create((SharedMemNames::formatTextInfo % dwConsoleProcessId).str(), 1, syncObjBoth); + m_consoleTextInfo.Create((SharedMemNames::formatTextInfo % dwConsoleProcessId).str(), 1, syncObjBoth, strUser); // mouse event - m_consoleMouseEvent.Create((SharedMemNames::formatMouseEvent % dwConsoleProcessId).str(), 1, syncObjBoth); + m_consoleMouseEvent.Create((SharedMemNames::formatMouseEvent % dwConsoleProcessId).str(), 1, syncObjBoth, strUser); // new console size - m_newConsoleSize.Create((SharedMemNames::formatNewConsoleSize % dwConsoleProcessId).str(), 1, syncObjRequest); + m_newConsoleSize.Create((SharedMemNames::formatNewConsoleSize % dwConsoleProcessId).str(), 1, syncObjRequest, strUser); // new scroll position - m_newScrollPos.Create((SharedMemNames::formatNewScrollPos % dwConsoleProcessId).str(), 1, syncObjRequest); + m_newScrollPos.Create((SharedMemNames::formatNewScrollPos % dwConsoleProcessId).str(), 1, syncObjRequest, strUser); // TODO: separate function for default settings m_consoleParams->dwRows = 25; m_consoleParams->dwColumns = 80; - return true; } @@ -689,11 +702,8 @@ DWORD WINAPI ConsoleHandler::MonitorThreadStatic(LPVOID lpParameter) DWORD ConsoleHandler::MonitorThread() { - { - // resume hook monitor thread - shared_ptr hHookMonitorThread(::OpenThread(THREAD_ALL_ACCESS, FALSE, m_consoleParams->dwHookThreadId), ::CloseHandle); - ::ResumeThread(hHookMonitorThread.get()); - } + // resume ConsoleHook's thread + m_consoleParams.SetRespEvent(); HANDLE arrWaitHandles[] = { m_hConsoleProcess.get(), m_hMonitorThreadExit.get(), m_consoleBuffer.GetReqEvent() }; while (::WaitForMultipleObjects(sizeof(arrWaitHandles)/sizeof(arrWaitHandles[0]), arrWaitHandles, FALSE, INFINITE) > WAIT_OBJECT_0 + 1) diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index f860c3f5..9a22d6d7 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -58,7 +58,7 @@ class ConsoleHandler private: - bool CreateSharedObjects(DWORD dwConsoleProcessId); + bool CreateSharedObjects(DWORD dwConsoleProcessId, const wstring& strUser); bool InjectHookDLL(PROCESS_INFORMATION& pi); diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index ca512dcb..40ed7036 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -5,6 +5,7 @@ #include "Console.h" #include "MainFrame.h" +#include "ConsoleException.h" #include "ConsoleView.h" ////////////////////////////////////////////////////////////////////////////// @@ -160,16 +161,24 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam* wstring strPassword(m_tabData->strUser.length() > 0 ? L"games" : L""); - if (!m_consoleHandler.StartShellProcess( - strShell, - strInitialDir, - m_tabData->strUser, - strPassword, - m_strInitialCmd, - g_settingsHandler->GetAppearanceSettings().windowSettings.bUseConsoleTitle ? m_tabData->strTitle : wstring(L""), - m_dwStartupRows, - m_dwStartupColumns, - bDebugFlag)) + try + { + m_consoleHandler.StartShellProcess( + strShell, + strInitialDir, + m_tabData->strUser, + strPassword, + m_strInitialCmd, + g_settingsHandler->GetAppearanceSettings().windowSettings.bUseConsoleTitle ? m_tabData->strTitle : wstring(L""), + m_dwStartupRows, + m_dwStartupColumns, + bDebugFlag); +/* { + return -1; + } +*/ + } + catch (const ConsoleException& ex) { return -1; } diff --git a/Console/DlgCredentials.cpp b/Console/DlgCredentials.cpp new file mode 100644 index 00000000..c23cb9e8 --- /dev/null +++ b/Console/DlgCredentials.cpp @@ -0,0 +1,69 @@ +#include "stdafx.h" +#include "resource.h" + +#include "DlgCredentials.h" + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +DlgCredentials::DlgCredentials(const CString& user) +: m_user(user) +, m_password() +{ +} + +////////////////////////////////////////////////////////////////////////////// + +DlgCredentials::~DlgCredentials() +{ +/* + if (m_password.GetLength() > 0) + { + ::SecureZeroMemory(reinterpret_cast(const_cast(m_password.GetString())), m_password.GetLength()); + } +*/ +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT DlgCredentials::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + DoDataExchange(DDX_LOAD); + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT DlgCredentials::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if (wID == IDOK) + { + DoDataExchange(DDX_SAVE); + } + + EndDialog(wID); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + diff --git a/Console/DlgCredentials.h b/Console/DlgCredentials.h new file mode 100644 index 00000000..e274fd27 --- /dev/null +++ b/Console/DlgCredentials.h @@ -0,0 +1,55 @@ + +#pragma once + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +class DlgCredentials + : public CDialogImpl + , public CWinDataExchange +{ + public: + enum { IDD = IDD_CREDENTIALS }; + + DlgCredentials(const CString& user); + ~DlgCredentials(); + + BEGIN_DDX_MAP(DlgCredentials) + DDX_TEXT(IDC_USER, m_user) + DDX_TEXT(IDC_PASSWORD, m_password) + END_DDX_MAP() + + BEGIN_MSG_MAP(DlgCredentials) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_ID_HANDLER(IDOK, OnCloseCmd) + COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) + END_MSG_MAP() + +// Handler prototypes (uncomment arguments if needed): +// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + + const CString& GetUser() const { return m_user; } + const CString& GetPassword() const { return m_password; } + + private: + + + private: + + CString m_user; + CString m_password; +}; + +////////////////////////////////////////////////////////////////////////////// diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index c4660674..eb73ca29 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -4,6 +4,7 @@ #include "aboutdlg.h" #include "Console.h" #include "ConsoleView.h" +#include "ConsoleException.h" #include "DlgRenameTab.h" #include "DlgSettingsMain.h" #include "MainFrame.h" @@ -1606,7 +1607,6 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir NULL, WS_CHILD | WS_VISIBLE,// | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0); - if (hwndConsoleView == NULL) { CString strMessage; diff --git a/Console/resource.h b/Console/resource.h index 9865e5ee..974fb4bb 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -20,6 +20,7 @@ #define IDD_SETTINGS_TABS_1 213 #define IDD_SETTINGS_TABS_2 214 #define IDD_SETTINGS_MOUSE 215 +#define IDD_CREDENTIALS 216 #define IDC_TAB_NAME 1000 #define IDC_APPLY 1001 #define IDC_TREE_SECTIONS 1002 @@ -216,8 +217,11 @@ #define IDC_CHECK_DEFAULT_ICON 1172 #define IDC_CHECK_TABS_ON_BOTTOM 1173 #define IDC_TAB_USER 1174 -#define IDC_APPTEXT 1175 -#define IDC_APPICON 1176 +#define IDC_USERNAME 1175 +#define IDC_USER 1175 +#define IDC_PASSWORD 1176 +#define IDC_APPTEXT 1177 +#define IDC_APPICON 1178 #define ID_NEW_TAB_1 2000 #define ID_SWITCH_TAB_1 2100 #define ID_NEXT_TAB 2200 @@ -242,9 +246,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 215 +#define _APS_NEXT_RESOURCE_VALUE 217 #define _APS_NEXT_COMMAND_VALUE 32794 -#define _APS_NEXT_CONTROL_VALUE 1177 +#define _APS_NEXT_CONTROL_VALUE 1179 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index ee131286..97607891 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -780,7 +780,7 @@ DWORD ConsoleHandler::MonitorThread() // read parent process ID and get process handle m_hParentProcess = shared_ptr( - ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_consoleParams->dwParentProcessId), + ::OpenProcess(SYNCHRONIZE, FALSE, m_consoleParams->dwParentProcessId), ::CloseHandle); TRACE(L"Parent process handle: 0x%08X\n", m_hParentProcess.get()); @@ -805,7 +805,7 @@ DWORD ConsoleHandler::MonitorThread() SetConsoleParams(::GetCurrentThreadId(), hStdOut); - ::SuspendThread(GetCurrentThread()); + if (::WaitForSingleObject(m_consoleParams.GetRespEvent(), 10000) == WAIT_TIMEOUT) return 0; ResizeConsoleWindow(hStdOut, m_consoleParams->dwColumns, m_consoleParams->dwRows, 0); @@ -821,7 +821,7 @@ DWORD ConsoleHandler::MonitorThread() m_consoleMouseEvent.GetReqEvent(), m_newConsoleSize.GetReqEvent(), hStdOut, - m_hParentProcess.get() +// m_hParentProcess.get() }; DWORD dwWaitRes = 0; diff --git a/shared/SharedMemory.h b/shared/SharedMemory.h index 706c82eb..45aea2ee 100644 --- a/shared/SharedMemory.h +++ b/shared/SharedMemory.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + ////////////////////////////////////////////////////////////////////////////// @@ -26,7 +29,7 @@ class SharedMemory ~SharedMemory(); - void Create(const wstring& strName, DWORD dwSize/* = 1*/, SyncObjectTypes syncObjects); + void Create(const wstring& strName, DWORD dwSize/* = 1*/, SyncObjectTypes syncObjects, const wstring& strUser); void Open(const wstring& strName, SyncObjectTypes syncObjects/* = syncObjNone*/); inline void Lock(); @@ -45,7 +48,7 @@ class SharedMemory private: - void CreateSyncObjects(SyncObjectTypes syncObjects, const wstring& strName); + void CreateSyncObjects(const shared_ptr& sa, SyncObjectTypes syncObjects, const wstring& strName); private: @@ -144,14 +147,254 @@ SharedMemory::~SharedMemory() ////////////////////////////////////////////////////////////////////////////// template -void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTypes syncObjects) +void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTypes syncObjects, const wstring& strUser) { m_strName = strName; m_dwSize = dwSize; + shared_ptr sa; + EXPLICIT_ACCESS ea[2]; + + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; + SID_IDENTIFIER_AUTHORITY SIDAuthCreator = SECURITY_CREATOR_SID_AUTHORITY; + + PSID tmpSID = NULL; + shared_ptr everyoneSID; // PSID + shared_ptr creatorSID; // PSID + + PACL tmpACL = NULL; + shared_ptr acl; + + shared_ptr sd; // PSECURITY_DESCRIPTOR + + ::ZeroMemory(&ea, 2*sizeof(EXPLICIT_ACCESS)); + + if (strUser.length() > 0) + { + // create a well-known SID for the Everyone group + if (!::AllocateAndInitializeSid( + &SIDAuthWorld, + 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &tmpSID)) + { + // TODO: error handling + return; + } + + everyoneSID.reset(tmpSID, ::FreeSid); + + // initialize an EXPLICIT_ACCESS structure for an ACE + // the ACE will allow Everyone full access + //ea[0].grfAccessPermissions = GENERIC_ALL; + //ea[0].grfAccessMode = SET_ACCESS; + //ea[0].grfInheritance = NO_INHERITANCE; + //ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; //TRUSTEE_IS_NAME;// TRUSTEE_IS_SID; + //ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;// TRUSTEE_IS_USER; // TRUSTEE_IS_WELL_KNOWN_GROUP; + //ea[0].Trustee.ptstrName = (LPTSTR)everyoneSID.get(); // (LPTSTR)strUsername.c_str(); + + // initialize an EXPLICIT_ACCESS structure for an ACE + // the ACE will allow Everyone full access + ea[0].grfAccessPermissions = GENERIC_ALL; + ea[0].grfAccessMode = SET_ACCESS; + ea[0].grfInheritance = NO_INHERITANCE; + ea[0].Trustee.TrusteeForm = TRUSTEE_IS_NAME; + ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER; + ea[0].Trustee.ptstrName = (LPTSTR)strUser.c_str(); + + // create a SID for the BUILTIN\Administrators group + if (!::AllocateAndInitializeSid( + &SIDAuthCreator, + 1, + SECURITY_CREATOR_OWNER_RID, + 0, 0, 0, 0, 0, 0, 0, + &tmpSID)) + { + // TODO: error handling + return; + } + + creatorSID.reset(tmpSID, ::FreeSid); + + // initialize an EXPLICIT_ACCESS structure for an ACE + // the ACE will allow the Administrators group full access + ea[1].grfAccessPermissions = GENERIC_ALL; + ea[1].grfAccessMode = SET_ACCESS; + ea[1].grfInheritance = NO_INHERITANCE; + ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ea[1].Trustee.ptstrName = (LPTSTR)creatorSID.get(); + + + /* + // create a SID for the BUILTIN\Administrators group + if (!::AllocateAndInitializeSid( + &SIDAuthNT, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &tmpSID)) + { + // TODO: error handling + return; + } + + creatorSID.reset(tmpSID, ::FreeSid); + + // Initialize an EXPLICIT_ACCESS structure for an ACE. + // The ACE will allow the Administrators group full access + ea[1].grfAccessPermissions = GENERIC_ALL; + ea[1].grfAccessMode = SET_ACCESS; + ea[1].grfInheritance = NO_INHERITANCE; + ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; + ea[1].Trustee.ptstrName = (LPTSTR)creatorSID.get(); + */ + + + // create a new ACL that contains the new ACEs + if (::SetEntriesInAcl(2, ea, NULL, &tmpACL) != ERROR_SUCCESS) + { + // TODO: error handling + return; + } + + acl.reset(tmpACL, ::LocalFree); + + // initialize a security descriptor + sd.reset(::LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH), ::LocalFree); + if (!sd) + { + // TODO: error handling + return; + } + + if (!::InitializeSecurityDescriptor(sd.get(), SECURITY_DESCRIPTOR_REVISION)) + { + // TODO: error handling + return; + } + + // add the ACL to the security descriptor + if (!::SetSecurityDescriptorDacl( + sd.get(), + TRUE, // bDaclPresent flag + acl.get(), + FALSE)) // not a default DACL + { + // TODO: error handling + return; + } + + // initialize a security attributes structure + sa.reset(new SECURITY_ATTRIBUTES); + sa->nLength = sizeof (SECURITY_ATTRIBUTES); + sa->lpSecurityDescriptor = sd.get(); + sa->bInheritHandle = FALSE; + } + +/* + + DWORD dwRes, dwDisposition; + PSID pEveryoneSID = NULL, pcreatorSID = NULL; + PACL pACL = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + EXPLICIT_ACCESS ea[2]; + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; + SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; + SECURITY_ATTRIBUTES sa; + LONG lRes; + HKEY hkSub = NULL; + + // Create a well-known SID for the Everyone group. + if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &pEveryoneSID)) + { + printf("AllocateAndInitializeSid Error %u\n", GetLastError()); + goto Cleanup; + } + + // Initialize an EXPLICIT_ACCESS structure for an ACE. + // The ACE will allow Everyone read access to the key. + ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS)); + ea[0].grfAccessPermissions = GENERIC_ALL; + ea[0].grfAccessMode = SET_ACCESS; + ea[0].grfInheritance= NO_INHERITANCE; + ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; //TRUSTEE_IS_NAME;// TRUSTEE_IS_SID; + ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;// TRUSTEE_IS_USER; // TRUSTEE_IS_WELL_KNOWN_GROUP; + ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID; // (LPTSTR)strUsername.c_str(); // (LPTSTR) pEveryoneSID; + + // Create a SID for the BUILTIN\Administrators group. + if(! AllocateAndInitializeSid(&SIDAuthNT, 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &pcreatorSID)) + { + printf("AllocateAndInitializeSid Error %u\n", GetLastError()); + goto Cleanup; + } + + // Initialize an EXPLICIT_ACCESS structure for an ACE. + // The ACE will allow the Administrators group full access to + // the key. + ea[1].grfAccessPermissions = GENERIC_ALL; + ea[1].grfAccessMode = SET_ACCESS; + ea[1].grfInheritance= NO_INHERITANCE; + ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; + ea[1].Trustee.ptstrName = (LPTSTR) pcreatorSID; + + // Create a new ACL that contains the new ACEs. + dwRes = SetEntriesInAcl(2, ea, NULL, &pACL); + if (ERROR_SUCCESS != dwRes) + { + printf("SetEntriesInAcl Error %u\n", GetLastError()); + goto Cleanup; + } + + // Initialize a security descriptor. + pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, + SECURITY_DESCRIPTOR_MIN_LENGTH); + if (NULL == pSD) + { + printf("LocalAlloc Error %u\n", GetLastError()); + goto Cleanup; + } + + if (!InitializeSecurityDescriptor(pSD, + SECURITY_DESCRIPTOR_REVISION)) + { + printf("InitializeSecurityDescriptor Error %u\n", + GetLastError()); + goto Cleanup; + } + + // Add the ACL to the security descriptor. + if (!SetSecurityDescriptorDacl(pSD, + TRUE, // bDaclPresent flag + pACL, + FALSE)) // not a default DACL + { + printf("SetSecurityDescriptorDacl Error %u\n", + GetLastError()); + goto Cleanup; + } + + // Initialize a security attributes structure. + sa.nLength = sizeof (SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; +*/ + m_hSharedMem = shared_ptr(::CreateFileMapping( INVALID_HANDLE_VALUE, - NULL, +// NULL, + sa.get(), PAGE_READWRITE, 0, m_dwSize * sizeof(T), @@ -171,9 +414,7 @@ void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTyp ::ZeroMemory(m_pSharedMem.get(), m_dwSize * sizeof(T)); - if (syncObjects > syncObjNone) CreateSyncObjects(syncObjects, strName); - - //if (!m_pSharedMem) return false; + if (syncObjects > syncObjNone) CreateSyncObjects(sa, syncObjects, strName); } ////////////////////////////////////////////////////////////////////////////// @@ -194,6 +435,7 @@ void SharedMemory::Open(const wstring& strName, SyncObjectTypes syncObjects) // TODO: error handling //if (!m_hSharedMem) return false; + if (!m_hSharedMem || (m_hSharedMem.get() == INVALID_HANDLE_VALUE)) OutputDebugString(str(wformat(L"Error opening shared mem %1%, error: %2%\n") % m_strName % ::GetLastError()).c_str()); m_pSharedMem = shared_ptr(static_cast(::MapViewOfFile( m_hSharedMem.get(), @@ -203,7 +445,9 @@ void SharedMemory::Open(const wstring& strName, SyncObjectTypes syncObjects) 0)), ::UnmapViewOfFile); - if (syncObjects > syncObjNone) CreateSyncObjects(syncObjects, strName); + if (!m_pSharedMem) OutputDebugString(str(wformat(L"Error mapping shared mem %1%, error: %2%\n") % m_strName % ::GetLastError()).c_str()); + + if (syncObjects > syncObjNone) CreateSyncObjects(shared_ptr(), syncObjects, strName); //if (!m_pSharedMem) return false; } @@ -240,8 +484,16 @@ void SharedMemory::Release() template void SharedMemory::SetReqEvent() { - if (!m_hSharedReqEvent) return; - ::SetEvent(m_hSharedReqEvent.get()); + if (!m_hSharedReqEvent) + { + OutputDebugString(str(wformat(L"Req Event %1% is null!") % m_strName).c_str()); + return; + } + + if (!::SetEvent(m_hSharedReqEvent.get())) + { + OutputDebugString(str(wformat(L"SetEvent %1% failed: %2%!\n") % m_strName % ::GetLastError()).c_str()); + } } ////////////////////////////////////////////////////////////////////////////// @@ -252,7 +504,11 @@ void SharedMemory::SetReqEvent() template void SharedMemory::SetRespEvent() { - if (!m_hSharedRespEvent) return; + if (!m_hSharedRespEvent) + { + OutputDebugString(str(wformat(L"Resp Event %1% is null!") % m_strName).c_str()); + return; + } ::SetEvent(m_hSharedRespEvent.get()); } @@ -345,24 +601,30 @@ SharedMemory& SharedMemory::operator=(const T& val) ////////////////////////////////////////////////////////////////////////////// template -void SharedMemory::CreateSyncObjects(SyncObjectTypes syncObjects, const wstring& strName) +void SharedMemory::CreateSyncObjects(const shared_ptr& sa, SyncObjectTypes syncObjects, const wstring& strName) { if (syncObjects >= syncObjRequest) { m_hSharedMutex = shared_ptr( - ::CreateMutex(NULL, FALSE, (strName + wstring(L"_mutex")).c_str()), + ::CreateMutex(sa.get(), FALSE, (wstring(L"") + strName + wstring(L"_mutex")).c_str()), ::CloseHandle); + OutputDebugString(str(wformat(L"m_hSharedMutex %1%: %2%\n") % m_strName % (DWORD)(m_hSharedMutex.get())).c_str()); + m_hSharedReqEvent = shared_ptr( - ::CreateEvent(NULL, FALSE, FALSE, (strName + wstring(L"_req_event")).c_str()), + ::CreateEvent(sa.get(), FALSE, FALSE, (wstring(L"") + strName + wstring(L"_req_event")).c_str()), ::CloseHandle); + + OutputDebugString(str(wformat(L"m_hSharedReqEvent %1%: %2%\n") % m_strName % (DWORD)(m_hSharedReqEvent.get())).c_str()); } if (syncObjects >= syncObjBoth) { m_hSharedRespEvent = shared_ptr( - ::CreateEvent(NULL, FALSE, FALSE, (strName + wstring(L"_resp_event")).c_str()), + ::CreateEvent(sa.get(), FALSE, FALSE, (wstring(L"") + strName + wstring(L"_resp_event")).c_str()), ::CloseHandle); + + OutputDebugString(str(wformat(L"m_hSharedRespEvent %1%: %2%\n") % m_strName % (DWORD)(m_hSharedRespEvent.get())).c_str()); } } From 12671f67d210dbe8229d0d46041310b387aadcfc Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Wed, 15 Sep 2010 22:19:01 +0200 Subject: [PATCH 033/207] More progress with user credentials, better support for WindowsXP (calling LoadUserProfile now) --- Console/Console.rc | 4 ++-- Console/ConsoleHandler.cpp | 48 +++++++++++++++++++------------------- Console/ConsoleHandler.h | 28 ++++++++++++++++++++++ Console/ConsoleView.cpp | 17 ++++++-------- Console/ConsoleView.h | 2 +- Console/DlgCredentials.cpp | 9 +++++-- Console/DlgCredentials.h | 5 ++-- Console/Helpers.cpp | 6 ++--- Console/MainFrame.cpp | 19 +++++++++++++-- shared/Structures.h | 5 ++++ 10 files changed, 96 insertions(+), 47 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index d172c3e5..2ce1498a 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -45,12 +45,12 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Enter username and password" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "&Username:",IDC_STATIC,7,16,36,8 - EDITTEXT IDC_USER,54,13,146,14,ES_AUTOHSCROLL LTEXT "&Password:",IDC_STATIC,7,31,34,8 EDITTEXT IDC_PASSWORD,54,28,146,14,ES_PASSWORD | ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,93,58,50,14 PUSHBUTTON "Cancel",IDCANCEL,150,58,50,14 + LTEXT "&Username:",IDC_STATIC,7,16,36,8 + EDITTEXT IDC_USER,54,13,146,14,ES_AUTOHSCROLL END diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index f9968dde..594ab23c 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -89,8 +89,9 @@ bool ConsoleHandler::StartShellProcess wstring strUsername(strUser); wstring strDomain; - shared_ptr userToken; + shared_ptr userProfileKey; shared_ptr userEnvironment; + shared_ptr userToken; if (strUsername.length() > 0) { @@ -101,6 +102,7 @@ bool ConsoleHandler::StartShellProcess strUsername = strUsername.substr(pos+1); } + // logon user HANDLE hUserToken = NULL; ::LogonUser( strUsername.c_str(), @@ -112,12 +114,22 @@ bool ConsoleHandler::StartShellProcess userToken.reset(hUserToken, ::CloseHandle); + // load user's profile + // seems to be necessary on WinXP for environment strings' expainsion to work properly + PROFILEINFO userProfile; + ::ZeroMemory(&userProfile, sizeof(PROFILEINFO)); + userProfile.dwSize = sizeof(PROFILEINFO); + userProfile.lpUserName = const_cast(strUser.c_str()); + + ::LoadUserProfile(userToken.get(), &userProfile); + userProfileKey.reset(userProfile.hProfile, bind(::UnloadUserProfile, userToken.get(), _1)); + + // load user's environment void* pEnvironment = NULL; ::CreateEnvironmentBlock(&pEnvironment, userToken.get(), FALSE); userEnvironment.reset(pEnvironment, ::DestroyEnvironmentBlock); } - wstring strShellCmdLine(strCustomShell); if (strShellCmdLine.length() == 0) @@ -126,6 +138,7 @@ bool ConsoleHandler::StartShellProcess ::ZeroMemory(szComspec, MAX_PATH*sizeof(wchar_t)); + // TODO: resolve when running as another user if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0) { strShellCmdLine = szComspec; @@ -213,36 +226,23 @@ bool ConsoleHandler::StartShellProcess // TODO: not supported yet //if (bDebugFlag) dwStartupFlags |= DEBUG_PROCESS; - + if (strUsername.length() > 0) { if (!::CreateProcessWithLogonW( - L"games", - NULL, - L"games", + strUsername.c_str(), + strDomain.length() > 0 ? strDomain.c_str() : NULL, + strPassword.c_str(), LOGON_WITH_PROFILE, NULL, - L"cmd.exe", + const_cast(Helpers::ExpandEnvironmentStringsForUser(userToken, strShellCmdLine).c_str()), dwStartupFlags, - NULL, - NULL, + userEnvironment.get(), + (strStartupDir.length() > 0) ? const_cast(strStartupDir.c_str()) : NULL, &si, &pi)) - //if (!::CreateProcessWithLogonW( - // strUsername.c_str(), - // strDomain.length() > 0 ? strDomain.c_str() : NULL, - // strPassword.c_str(), - // LOGON_WITH_PROFILE, - // NULL, - // const_cast(Helpers::ExpandEnvironmentStringsForUser(userToken, strShellCmdLine).c_str()), - // dwStartupFlags, - // userEnvironment.get(), - // (strStartupDir.length() > 0) ? const_cast(strStartupDir.c_str()) : NULL, - // &si, - // &pi)) { - throw ConsoleException(str(wformat(L"Unable to start a shell as user %1%!") % strUser)); - //return false; + throw ConsoleException(str(wformat(L"Unable to start a %1% as user %2%!") % strShellCmdLine % strUser)); } } else @@ -259,7 +259,7 @@ bool ConsoleHandler::StartShellProcess &si, &pi)) { - return false; + throw ConsoleException(str(wformat(L"Unable to start a %1%!") % strShellCmdLine)); } } diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index 9a22d6d7..fa2e90a5 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -11,6 +11,34 @@ typedef fastdelegate::FastDelegate1 ConsoleChangeDelegate; typedef fastdelegate::FastDelegate0<> ConsoleCloseDelegate; +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +struct UserCredentials +{ + UserCredentials() + : user() + , password() + { + } + + ~UserCredentials() + { + if (password.length() > 0) + { + ::SecureZeroMemory(reinterpret_cast(const_cast(password.c_str())), password.length()); + } + } + + wstring user; + wstring password; +}; + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// class ConsoleHandler diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 40ed7036..e75353aa 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -106,7 +106,7 @@ BOOL ConsoleView::PreTranslateMessage(MSG* pMsg) ////////////////////////////////////////////////////////////////////////////// -LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { // set view title SetWindowText(m_strTitle); @@ -159,26 +159,23 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam* strShell = m_tabData->strShell; } - wstring strPassword(m_tabData->strUser.length() > 0 ? L"games" : L""); - try { + CREATESTRUCT* createStruct = reinterpret_cast(lParam); + UserCredentials* userCredentials = reinterpret_cast(createStruct->lpCreateParams); + m_consoleHandler.StartShellProcess( strShell, strInitialDir, - m_tabData->strUser, - strPassword, + userCredentials->user, + userCredentials->password, m_strInitialCmd, g_settingsHandler->GetAppearanceSettings().windowSettings.bUseConsoleTitle ? m_tabData->strTitle : wstring(L""), m_dwStartupRows, m_dwStartupColumns, bDebugFlag); -/* { - return -1; - } -*/ } - catch (const ConsoleException& ex) + catch (const ConsoleException& /*ex*/) { return -1; } diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index 76989e3a..fb9d1e27 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -75,7 +75,7 @@ class ConsoleView // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) - LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/); LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled); LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); diff --git a/Console/DlgCredentials.cpp b/Console/DlgCredentials.cpp index c23cb9e8..509a571a 100644 --- a/Console/DlgCredentials.cpp +++ b/Console/DlgCredentials.cpp @@ -19,18 +19,22 @@ DlgCredentials::DlgCredentials(const CString& user) { } +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// DlgCredentials::~DlgCredentials() { -/* if (m_password.GetLength() > 0) { ::SecureZeroMemory(reinterpret_cast(const_cast(m_password.GetString())), m_password.GetLength()); } -*/ } +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -41,6 +45,7 @@ DlgCredentials::~DlgCredentials() LRESULT DlgCredentials::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { DoDataExchange(DDX_LOAD); + GetDlgItem(IDC_PASSWORD).SetFocus(); return TRUE; } diff --git a/Console/DlgCredentials.h b/Console/DlgCredentials.h index e274fd27..fb9e8c22 100644 --- a/Console/DlgCredentials.h +++ b/Console/DlgCredentials.h @@ -40,12 +40,11 @@ class DlgCredentials LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + public: + const CString& GetUser() const { return m_user; } const CString& GetPassword() const { return m_password; } - private: - - private: CString m_user; diff --git a/Console/Helpers.cpp b/Console/Helpers.cpp index 3fa3c752..a8d051b5 100644 --- a/Console/Helpers.cpp +++ b/Console/Helpers.cpp @@ -45,10 +45,10 @@ wstring Helpers::ExpandEnvironmentStrings(const wstring& str) wstring Helpers::ExpandEnvironmentStringsForUser(const shared_ptr& userToken, const wstring& str) { - shared_array szExpanded(new wchar_t[0x8000]); + shared_array szExpanded(new wchar_t[MAX_PATH]); - ::ZeroMemory(szExpanded.get(), 0x8000*sizeof(wchar_t)); - ::ExpandEnvironmentStringsForUser(userToken.get(), str.c_str(), szExpanded.get(), 0x8000); + ::ZeroMemory(szExpanded.get(), MAX_PATH*sizeof(wchar_t)); + ::ExpandEnvironmentStringsForUser(userToken.get(), str.c_str(), szExpanded.get(), MAX_PATH); return wstring(szExpanded.get()); } diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index eb73ca29..c9ab8a0e 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -7,6 +7,7 @@ #include "ConsoleException.h" #include "DlgRenameTab.h" #include "DlgSettingsMain.h" +#include "DlgCredentials.h" #include "MainFrame.h" ////////////////////////////////////////////////////////////////////////////// @@ -1599,21 +1600,35 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir m_dwColumns = dwColumns; } + shared_ptr tabData = g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]; + shared_ptr consoleView(new ConsoleView(*this, dwTabIndex, strStartupDir, strStartupCmd, strDbgCmdLine, dwRows, dwColumns)); + UserCredentials userCredentials; + + if (tabData->strUser.length() > 0) + { + DlgCredentials dlg(tabData->strUser.c_str()); + + if (dlg.DoModal() != IDOK) return false; + + userCredentials.user = dlg.GetUser(); + userCredentials.password= dlg.GetPassword(); + } HWND hwndConsoleView = consoleView->Create( m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE,// | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, - 0); + 0, + 0U, + reinterpret_cast(&userCredentials)); if (hwndConsoleView == NULL) { CString strMessage; // copied from ConsoleView::OnCreate wstring strShell; - shared_ptr tabData = g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]; if (strDbgCmdLine.length() > 0) { strShell = strDbgCmdLine; diff --git a/shared/Structures.h b/shared/Structures.h index 0b3ea884..a06d5b62 100644 --- a/shared/Structures.h +++ b/shared/Structures.h @@ -200,3 +200,8 @@ struct TextInfo }; ////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// From 1208ebff3d52681c689ee43d2144f1928c9d027d Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Mon, 20 Sep 2010 18:02:33 +0100 Subject: [PATCH 034/207] Started work on nicer error messages --- Console/Console.rc | 6 ++++++ Console/ConsoleHandler.cpp | 5 +++-- Console/ConsoleView.cpp | 3 ++- Console/ConsoleView.h | 8 ++++++++ Console/Helpers.cpp | 16 ++++++++++++++++ Console/Helpers.h | 1 + Console/MainFrame.cpp | 29 +++++++++++++++++------------ Console/resource.h | 4 +++- 8 files changed, 56 insertions(+), 16 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index 2ce1498a..eeb39419 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -957,6 +957,12 @@ BEGIN IDPANE_ROWS_COLUMNS "%ix%i" END +STRINGTABLE +BEGIN + IDS_ERR_CANT_START_SHELL "Unable to start a %1%!" + IDS_ERR_CANT_START_SHELL_AS_USER "Unable to start a %1% as user %2%!" +END + #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 594ab23c..8fd09147 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" +#include "resource.h" #include "Console.h" #include "../shared/SharedMemNames.h" @@ -242,7 +243,7 @@ bool ConsoleHandler::StartShellProcess &si, &pi)) { - throw ConsoleException(str(wformat(L"Unable to start a %1% as user %2%!") % strShellCmdLine % strUser)); + throw ConsoleException(str(wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % strShellCmdLine % strUser)); } } else @@ -259,7 +260,7 @@ bool ConsoleHandler::StartShellProcess &si, &pi)) { - throw ConsoleException(str(wformat(L"Unable to start a %1%!") % strShellCmdLine)); + throw ConsoleException(str(wformat(Helpers::LoadString(IDS_ERR_CANT_START_SHELL)) % strShellCmdLine)); } } diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index e75353aa..b67f69cd 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -175,8 +175,9 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B m_dwStartupColumns, bDebugFlag); } - catch (const ConsoleException& /*ex*/) + catch (const ConsoleException& ex) { + m_exceptionMessage = ex.GetMessage().c_str(); return -1; } diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index fb9d1e27..61361e5e 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -134,6 +134,8 @@ class ConsoleView void DumpBuffer(); void InitializeScrollbars(); + const CString& GetExceptionMessage() const { return m_exceptionMessage; } + private: void OnConsoleChange(bool bResize); @@ -163,6 +165,7 @@ class ConsoleView COORD GetConsoleCoord(const CPoint& clientPoint); + private: MainFrame& m_mainFrame; @@ -216,6 +219,11 @@ class ConsoleView bool m_bFlashTimerRunning; DWORD m_dwFlashes; + // since message handlers are not exception-safe, + // we'll store error messages thrown during OnCreate + // handler here... + CString m_exceptionMessage; + // static members private: diff --git a/Console/Helpers.cpp b/Console/Helpers.cpp index a8d051b5..8445a25a 100644 --- a/Console/Helpers.cpp +++ b/Console/Helpers.cpp @@ -153,6 +153,22 @@ HBITMAP Helpers::CreateBitmap(HDC dc, DWORD dwWidth, DWORD dwHeight, CBitmap& bi ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +wstring Helpers::LoadString(UINT uID) +{ + int bufferSize = 0x800; + scoped_array str(new wchar_t[bufferSize]); + ::ZeroMemory(str.get(), bufferSize * sizeof(wchar_t)); + + bufferSize = ::LoadString(::GetModuleHandle(NULL), uID, str.get(), bufferSize); + + return wstring(str.get()); +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// HICON Helpers::LoadTabIcon(bool bBigIcon, bool bUseDefaultIcon, const wstring& strIcon, const wstring& strShell) diff --git a/Console/Helpers.h b/Console/Helpers.h index 7409956c..4663d6df 100644 --- a/Console/Helpers.h +++ b/Console/Helpers.h @@ -25,6 +25,7 @@ class Helpers static HBITMAP CreateBitmap(HDC dc, DWORD dwWidth, DWORD dwHeight, CBitmap& bitmap); + static wstring LoadString(UINT uID); static HICON LoadTabIcon(bool bBigIcon, bool bUseDefaultIcon, const wstring& strIcon, const wstring& strShell); private: diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index c9ab8a0e..41072c17 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1623,23 +1623,28 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir 0, 0U, reinterpret_cast(&userCredentials)); + if (hwndConsoleView == NULL) { - CString strMessage; + CString strMessage(consoleView->GetExceptionMessage()); - // copied from ConsoleView::OnCreate - wstring strShell; - if (strDbgCmdLine.length() > 0) - { - strShell = strDbgCmdLine; - } - else if (tabData->strShell.length() > 0) + if (strMessage.GetLength() == 0) { - strShell = tabData->strShell; + // copied from ConsoleView::OnCreate + wstring strShell; + if (strDbgCmdLine.length() > 0) + { + strShell = strDbgCmdLine; + } + else if (tabData->strShell.length() > 0) + { + strShell = tabData->strShell; + } + // end of copy from ConsoleView::OnCreate + + strMessage.Format(IDS_TAB_CREATE_FAILED, g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]->strTitle.c_str(), strShell.c_str()); } - // end of copy from ConsoleView::OnCreate - - strMessage.Format(IDS_TAB_CREATE_FAILED, g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]->strTitle.c_str(), strShell.c_str()); + ::MessageBox(m_hWnd, strMessage, L"Error", MB_OK|MB_ICONERROR); return false; diff --git a/Console/resource.h b/Console/resource.h index 974fb4bb..edb68a2f 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -217,7 +217,6 @@ #define IDC_CHECK_DEFAULT_ICON 1172 #define IDC_CHECK_TABS_ON_BOTTOM 1173 #define IDC_TAB_USER 1174 -#define IDC_USERNAME 1175 #define IDC_USER 1175 #define IDC_PASSWORD 1176 #define IDC_APPTEXT 1177 @@ -228,6 +227,9 @@ #define ID_PREV_TAB 2201 #define ID_RENAME_TAB_OK 2202 #define IDC_DUMP_BUFFER 3000 +#define IDS_ERR_CANT_START_SHELL 5000 +#define IDS_ERR_CANT_START_AS_USER 5001 +#define IDS_ERR_CANT_START_SHELL_AS_USER 5001 #define ID_FILE_NEW_TAB 32775 #define ID_VIEW_CONSOLE 32777 #define ID_FILE_CLOSE_TAB 32779 From ec728907aef973561896c9005f0f256d0d6c78a6 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Mon, 20 Sep 2010 19:04:46 +0200 Subject: [PATCH 035/207] Code cleanup --- shared/SharedMemory.h | 151 ------------------------------------------ 1 file changed, 151 deletions(-) diff --git a/shared/SharedMemory.h b/shared/SharedMemory.h index 45aea2ee..17f66f09 100644 --- a/shared/SharedMemory.h +++ b/shared/SharedMemory.h @@ -155,11 +155,9 @@ void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTyp shared_ptr sa; EXPLICIT_ACCESS ea[2]; - SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY SIDAuthCreator = SECURITY_CREATOR_SID_AUTHORITY; PSID tmpSID = NULL; - shared_ptr everyoneSID; // PSID shared_ptr creatorSID; // PSID PACL tmpACL = NULL; @@ -171,29 +169,6 @@ void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTyp if (strUser.length() > 0) { - // create a well-known SID for the Everyone group - if (!::AllocateAndInitializeSid( - &SIDAuthWorld, - 1, - SECURITY_WORLD_RID, - 0, 0, 0, 0, 0, 0, 0, - &tmpSID)) - { - // TODO: error handling - return; - } - - everyoneSID.reset(tmpSID, ::FreeSid); - - // initialize an EXPLICIT_ACCESS structure for an ACE - // the ACE will allow Everyone full access - //ea[0].grfAccessPermissions = GENERIC_ALL; - //ea[0].grfAccessMode = SET_ACCESS; - //ea[0].grfInheritance = NO_INHERITANCE; - //ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; //TRUSTEE_IS_NAME;// TRUSTEE_IS_SID; - //ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;// TRUSTEE_IS_USER; // TRUSTEE_IS_WELL_KNOWN_GROUP; - //ea[0].Trustee.ptstrName = (LPTSTR)everyoneSID.get(); // (LPTSTR)strUsername.c_str(); - // initialize an EXPLICIT_ACCESS structure for an ACE // the ACE will allow Everyone full access ea[0].grfAccessPermissions = GENERIC_ALL; @@ -226,35 +201,6 @@ void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTyp ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[1].Trustee.ptstrName = (LPTSTR)creatorSID.get(); - - /* - // create a SID for the BUILTIN\Administrators group - if (!::AllocateAndInitializeSid( - &SIDAuthNT, - 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - &tmpSID)) - { - // TODO: error handling - return; - } - - creatorSID.reset(tmpSID, ::FreeSid); - - // Initialize an EXPLICIT_ACCESS structure for an ACE. - // The ACE will allow the Administrators group full access - ea[1].grfAccessPermissions = GENERIC_ALL; - ea[1].grfAccessMode = SET_ACCESS; - ea[1].grfInheritance = NO_INHERITANCE; - ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; - ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; - ea[1].Trustee.ptstrName = (LPTSTR)creatorSID.get(); - */ - - - // create a new ACL that contains the new ACEs if (::SetEntriesInAcl(2, ea, NULL, &tmpACL) != ERROR_SUCCESS) { // TODO: error handling @@ -295,105 +241,8 @@ void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTyp sa->bInheritHandle = FALSE; } -/* - - DWORD dwRes, dwDisposition; - PSID pEveryoneSID = NULL, pcreatorSID = NULL; - PACL pACL = NULL; - PSECURITY_DESCRIPTOR pSD = NULL; - EXPLICIT_ACCESS ea[2]; - SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; - SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; - SECURITY_ATTRIBUTES sa; - LONG lRes; - HKEY hkSub = NULL; - - // Create a well-known SID for the Everyone group. - if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, - SECURITY_WORLD_RID, - 0, 0, 0, 0, 0, 0, 0, - &pEveryoneSID)) - { - printf("AllocateAndInitializeSid Error %u\n", GetLastError()); - goto Cleanup; - } - - // Initialize an EXPLICIT_ACCESS structure for an ACE. - // The ACE will allow Everyone read access to the key. - ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS)); - ea[0].grfAccessPermissions = GENERIC_ALL; - ea[0].grfAccessMode = SET_ACCESS; - ea[0].grfInheritance= NO_INHERITANCE; - ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; //TRUSTEE_IS_NAME;// TRUSTEE_IS_SID; - ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;// TRUSTEE_IS_USER; // TRUSTEE_IS_WELL_KNOWN_GROUP; - ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID; // (LPTSTR)strUsername.c_str(); // (LPTSTR) pEveryoneSID; - - // Create a SID for the BUILTIN\Administrators group. - if(! AllocateAndInitializeSid(&SIDAuthNT, 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, 0, 0, 0, 0, 0, - &pcreatorSID)) - { - printf("AllocateAndInitializeSid Error %u\n", GetLastError()); - goto Cleanup; - } - - // Initialize an EXPLICIT_ACCESS structure for an ACE. - // The ACE will allow the Administrators group full access to - // the key. - ea[1].grfAccessPermissions = GENERIC_ALL; - ea[1].grfAccessMode = SET_ACCESS; - ea[1].grfInheritance= NO_INHERITANCE; - ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; - ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; - ea[1].Trustee.ptstrName = (LPTSTR) pcreatorSID; - - // Create a new ACL that contains the new ACEs. - dwRes = SetEntriesInAcl(2, ea, NULL, &pACL); - if (ERROR_SUCCESS != dwRes) - { - printf("SetEntriesInAcl Error %u\n", GetLastError()); - goto Cleanup; - } - - // Initialize a security descriptor. - pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, - SECURITY_DESCRIPTOR_MIN_LENGTH); - if (NULL == pSD) - { - printf("LocalAlloc Error %u\n", GetLastError()); - goto Cleanup; - } - - if (!InitializeSecurityDescriptor(pSD, - SECURITY_DESCRIPTOR_REVISION)) - { - printf("InitializeSecurityDescriptor Error %u\n", - GetLastError()); - goto Cleanup; - } - - // Add the ACL to the security descriptor. - if (!SetSecurityDescriptorDacl(pSD, - TRUE, // bDaclPresent flag - pACL, - FALSE)) // not a default DACL - { - printf("SetSecurityDescriptorDacl Error %u\n", - GetLastError()); - goto Cleanup; - } - - // Initialize a security attributes structure. - sa.nLength = sizeof (SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = pSD; - sa.bInheritHandle = FALSE; -*/ - m_hSharedMem = shared_ptr(::CreateFileMapping( INVALID_HANDLE_VALUE, -// NULL, sa.get(), PAGE_READWRITE, 0, From af11e2ef1df967f17d747ee8dd07c2c1bfe8f620 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Mon, 20 Sep 2010 19:09:19 +0200 Subject: [PATCH 036/207] The credentials dialog is now centered in the main Console window --- Console/DlgCredentials.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Console/DlgCredentials.cpp b/Console/DlgCredentials.cpp index 509a571a..71c9809c 100644 --- a/Console/DlgCredentials.cpp +++ b/Console/DlgCredentials.cpp @@ -46,6 +46,9 @@ LRESULT DlgCredentials::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /* { DoDataExchange(DDX_LOAD); GetDlgItem(IDC_PASSWORD).SetFocus(); + + CenterWindow(); + return TRUE; } From f2e80d690c3d58c01c8c58c4519266ceef41d39d Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Tue, 21 Sep 2010 12:05:57 +0200 Subject: [PATCH 037/207] Title formatting for tabs running under different users --- Console/ConsoleView.cpp | 24 +++++++++++++++--------- Console/ConsoleView.h | 3 ++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index b67f69cd..c484face 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -47,6 +47,7 @@ ConsoleView::ConsoleView(MainFrame& mainFrame, DWORD dwTabIndex, const wstring& , m_nVScrollWidth(::GetSystemMetrics(SM_CXVSCROLL)) , m_nHScrollWidth(::GetSystemMetrics(SM_CXHSCROLL)) , m_strTitle(g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]->strTitle.c_str()) +, m_strUser() , bigIcon() , smallIcon() , m_consoleHandler() @@ -108,9 +109,6 @@ BOOL ConsoleView::PreTranslateMessage(MSG* pMsg) LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { - // set view title - SetWindowText(m_strTitle); - DragAcceptFiles(TRUE); // load icon @@ -174,6 +172,8 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B m_dwStartupRows, m_dwStartupColumns, bDebugFlag); + + m_strUser = userCredentials->user.c_str(); } catch (const ConsoleException& ex) { @@ -181,6 +181,9 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B return -1; } + // set view title + SetTitle(m_strTitle); + m_bInitializing = false; // set current language in the console window @@ -1143,7 +1146,14 @@ void ConsoleView::SetActive(bool bActive) void ConsoleView::SetTitle(const CString& strTitle) { - m_strTitle = strTitle; + CString title(strTitle); + + if (m_strUser.GetLength() > 0) + { + title.Format(L"[%s] %s", m_strUser, strTitle); + } + + m_strTitle = title; SetWindowText(m_strTitle); } @@ -1640,11 +1650,7 @@ void ConsoleView::UpdateTitle() consoleWnd.GetWindowText(strConsoleTitle); - // if we're using console titles, update the title - if (strConsoleTitle == m_strTitle) return; - - m_strTitle = strConsoleTitle; - SetWindowText(m_strTitle); + SetTitle(strConsoleTitle); } m_mainFrame.PostMessage( diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index 61361e5e..5f26f1f8 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -118,9 +118,9 @@ class ConsoleView void SetResizing(bool bResizing); void SetActive(bool bActive); void SetTitle(const CString& strTitle); + const CString& GetTitle() const { return m_strTitle; } CString GetConsoleCommand(); - const CString& GetTitle() const { return m_strTitle; } CIcon& GetIcon(bool bBigIcon = true) { return bBigIcon ? bigIcon : smallIcon; } void Copy(const CPoint* pPoint = NULL); @@ -191,6 +191,7 @@ class ConsoleView int m_nHScrollWidth; CString m_strTitle; + CString m_strUser; CIcon bigIcon; CIcon smallIcon; From f9d2c64f1137826db3b9023a369eb28f13aea35a Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Thu, 23 Sep 2010 15:58:33 +0200 Subject: [PATCH 038/207] - proper comspec resolution for shells running under different user --- Console/ConsoleHandler.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 8fd09147..bd3d59e3 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -139,14 +139,28 @@ bool ConsoleHandler::StartShellProcess ::ZeroMemory(szComspec, MAX_PATH*sizeof(wchar_t)); - // TODO: resolve when running as another user - if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0) + if (strUsername.length() > 0) { - strShellCmdLine = szComspec; + // resolve comspec when running as another user + wchar_t* pszComspec = reinterpret_cast(userEnvironment.get()); + + while ((pszComspec[0] != L'\x00') && (_wcsnicmp(pszComspec, L"comspec", 7) != 0)) pszComspec += wcslen(pszComspec)+1; + + if (pszComspec[0] != L'\x00') + { + strShellCmdLine = (pszComspec + 8); + } + + if (strShellCmdLine.length() == 0) strShellCmdLine = L"cmd.exe"; } else { - strShellCmdLine = L"cmd.exe"; + if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0) + { + strShellCmdLine = szComspec; + } + + if (strShellCmdLine.length() == 0) strShellCmdLine = L"cmd.exe"; } } From 9158aa38afaf5faaa6e5af78bd54ec5451d4a06d Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 25 Sep 2010 22:49:04 +0200 Subject: [PATCH 039/207] fix usage on VISTA previous code worked only with admin credentials --- Console/ConsoleHandler.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index bd3d59e3..0ac94918 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -71,7 +71,6 @@ void ConsoleHandler::SetupDelegates(ConsoleChangeDelegate consoleChangeDelegate, ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// bool ConsoleHandler::StartShellProcess @@ -105,29 +104,37 @@ bool ConsoleHandler::StartShellProcess // logon user HANDLE hUserToken = NULL; - ::LogonUser( + if( !::LogonUser( strUsername.c_str(), strDomain.length() > 0 ? strDomain.c_str() : NULL, strPassword.c_str(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, - &hUserToken); - + &hUserToken) || !::ImpersonateLoggedOnUser(hUserToken) ) + { + throw ConsoleException(str(wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % L"?" % strUser)); + } userToken.reset(hUserToken, ::CloseHandle); +/* // load user's profile // seems to be necessary on WinXP for environment strings' expainsion to work properly PROFILEINFO userProfile; ::ZeroMemory(&userProfile, sizeof(PROFILEINFO)); userProfile.dwSize = sizeof(PROFILEINFO); userProfile.lpUserName = const_cast(strUser.c_str()); - + ::LoadUserProfile(userToken.get(), &userProfile); userProfileKey.reset(userProfile.hProfile, bind(::UnloadUserProfile, userToken.get(), _1)); +*/ // load user's environment void* pEnvironment = NULL; - ::CreateEnvironmentBlock(&pEnvironment, userToken.get(), FALSE); + if( !::CreateEnvironmentBlock(&pEnvironment, userToken.get(), FALSE) ) + { + ::RevertToSelf(); + throw ConsoleException(str(wformat(Helpers::LoadStringW(IDS_ERR_CANT_START_SHELL_AS_USER)) % L"?" % strUser)); + } userEnvironment.reset(pEnvironment, ::DestroyEnvironmentBlock); } @@ -157,7 +164,7 @@ bool ConsoleHandler::StartShellProcess { if (::GetEnvironmentVariable(L"COMSPEC", szComspec, MAX_PATH) > 0) { - strShellCmdLine = szComspec; + strShellCmdLine = szComspec; } if (strShellCmdLine.length() == 0) strShellCmdLine = L"cmd.exe"; @@ -233,7 +240,7 @@ bool ConsoleHandler::StartShellProcess si.dwX = 0x7FFF; si.dwY = 0x7FFF; } - + PROCESS_INFORMATION pi; // we must use CREATE_UNICODE_ENVIRONMENT here, since s_environmentBlock contains Unicode strings DWORD dwStartupFlags = CREATE_NEW_CONSOLE|CREATE_SUSPENDED|CREATE_UNICODE_ENVIRONMENT; @@ -241,18 +248,19 @@ bool ConsoleHandler::StartShellProcess // TODO: not supported yet //if (bDebugFlag) dwStartupFlags |= DEBUG_PROCESS; - if (strUsername.length() > 0) { - if (!::CreateProcessWithLogonW( + wstring strCmdLine = Helpers::ExpandEnvironmentStringsForUser(userToken, strShellCmdLine); + ::RevertToSelf(); + if( !::CreateProcessWithLogonW( strUsername.c_str(), strDomain.length() > 0 ? strDomain.c_str() : NULL, strPassword.c_str(), LOGON_WITH_PROFILE, NULL, - const_cast(Helpers::ExpandEnvironmentStringsForUser(userToken, strShellCmdLine).c_str()), + const_cast(strCmdLine.c_str()), dwStartupFlags, - userEnvironment.get(), + NULL, (strStartupDir.length() > 0) ? const_cast(strStartupDir.c_str()) : NULL, &si, &pi)) From 41c45520e0888cfd4f06d37450e099615984e6c4 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 25 Sep 2010 23:36:19 +0200 Subject: [PATCH 040/207] AERO glass style for credentials dialog --- Console/Console.rc | 7 ++++--- Console/DlgCredentials.cpp | 9 +++++++++ Console/DlgCredentials.h | 11 +++++++++-- Console/resource.h | 2 ++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index eeb39419..b7060a7f 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -45,11 +45,11 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Enter username and password" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - LTEXT "&Password:",IDC_STATIC,7,31,34,8 + CTEXT "\n&Password:",IDC_STATIC_PASSWORD,7,22,42,22 EDITTEXT IDC_PASSWORD,54,28,146,14,ES_PASSWORD | ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,93,58,50,14 PUSHBUTTON "Cancel",IDCANCEL,150,58,50,14 - LTEXT "&Username:",IDC_STATIC,7,16,36,8 + CTEXT "\n&Username:",IDC_STATIC_USER,7,8,42,22 EDITTEXT IDC_USER,54,13,146,14,ES_AUTOHSCROLL END @@ -973,7 +973,8 @@ END // // Generated from the TEXTINCLUDE 3 resource. // - + + ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/Console/DlgCredentials.cpp b/Console/DlgCredentials.cpp index 71c9809c..3f5ead79 100644 --- a/Console/DlgCredentials.cpp +++ b/Console/DlgCredentials.cpp @@ -49,6 +49,15 @@ LRESULT DlgCredentials::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /* CenterWindow(); +#ifdef _USE_AERO + AERO_CONTROL(CStatic, m_LabelUser, IDC_STATIC_USER) + AERO_CONTROL(CStatic, m_LabelPassword, IDC_STATIC_PASSWORD) + AERO_CONTROL(CEdit, m_EditPassword, IDC_PASSWORD) + AERO_CONTROL(CEdit, m_EditUser, IDC_USER) + AERO_CONTROL(CButton, m_Cancel, IDCANCEL) + AERO_CONTROL(CButton, m_Ok, IDOK) +#endif + return TRUE; } diff --git a/Console/DlgCredentials.h b/Console/DlgCredentials.h index fb9e8c22..6b450cbe 100644 --- a/Console/DlgCredentials.h +++ b/Console/DlgCredentials.h @@ -11,8 +11,12 @@ ////////////////////////////////////////////////////////////////////////////// -class DlgCredentials - : public CDialogImpl +class DlgCredentials +#ifdef _USE_AERO + : public aero::CDialogImpl +#else + : public CDialogImpl +#endif , public CWinDataExchange { public: @@ -27,6 +31,9 @@ class DlgCredentials END_DDX_MAP() BEGIN_MSG_MAP(DlgCredentials) +#ifdef _USE_AERO + CHAIN_MSG_MAP(aero::CDialogImpl) +#endif MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_ID_HANDLER(IDOK, OnCloseCmd) COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) diff --git a/Console/resource.h b/Console/resource.h index edb68a2f..41ada49f 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -220,7 +220,9 @@ #define IDC_USER 1175 #define IDC_PASSWORD 1176 #define IDC_APPTEXT 1177 +#define IDC_STATIC_USER 1177 #define IDC_APPICON 1178 +#define IDC_STATIC_PASSWORD 1178 #define ID_NEW_TAB_1 2000 #define ID_SWITCH_TAB_1 2100 #define ID_NEXT_TAB 2200 From db9cd96c80bd61d4abb77ca825aa77c2118825a3 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 26 Sep 2010 19:29:54 +0200 Subject: [PATCH 041/207] use of CredUIPromptForCredentials password is stored in multiple buffers, it's not safe ... --- Console/Console.vcproj | 2 +- Console/MainFrame.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ Console/stdafx.h | 1 + 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/Console/Console.vcproj b/Console/Console.vcproj index 316dd38b..0f3a0890 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -438,7 +438,7 @@ /> strUser.length() > 0) { +#ifdef _USE_AERO + // Display a dialog box to request credentials. + CREDUI_INFOW ui; + ui.cbSize = sizeof(ui); + ui.hwndParent = GetConsoleWindow(); + ui.pszMessageText = tabData->strShell.c_str(); + ui.pszCaptionText = L"Enter username and password"; + ui.hbmBanner = NULL; + + // we need a target + WCHAR szModuleFileName[_MAX_PATH] = L""; + ::GetModuleFileName(NULL, szModuleFileName, ARRAYSIZE(szModuleFileName)); + + WCHAR szUser [CREDUI_MAX_USERNAME_LENGTH + 1] = L""; + WCHAR szPassword[CREDUI_MAX_PASSWORD_LENGTH + 1] = L""; + wcscpy_s(szUser, ARRAYSIZE(szUser), tabData->strUser.c_str()); + + DWORD rc = ::CredUIPromptForCredentials( + &ui, //__in_opt PCREDUI_INFO pUiInfo, + szModuleFileName, //__in PCTSTR pszTargetName, + NULL, //__in PCtxtHandle Reserved, + 0, //__in_opt DWORD dwAuthError, + szUser, //__inout PCTSTR pszUserName, + ARRAYSIZE(szUser), //__in ULONG ulUserNameMaxChars, + szPassword, //__inout PCTSTR pszPassword, + ARRAYSIZE(szPassword), //__in ULONG ulPasswordMaxChars, + NULL, //__inout PBOOL pfSave, + CREDUI_FLAGS_EXCLUDE_CERTIFICATES | //__in DWORD dwFlags + CREDUI_FLAGS_ALWAYS_SHOW_UI | + CREDUI_FLAGS_GENERIC_CREDENTIALS | + CREDUI_FLAGS_DO_NOT_PERSIST + ); + + if( rc != NO_ERROR ) + return false; + + userCredentials.user = szUser; + userCredentials.password = szPassword; +#else DlgCredentials dlg(tabData->strUser.c_str()); if (dlg.DoModal() != IDOK) return false; userCredentials.user = dlg.GetUser(); userCredentials.password= dlg.GetPassword(); +#endif } HWND hwndConsoleView = consoleView->Create( diff --git a/Console/stdafx.h b/Console/stdafx.h index 052ac785..6d32559c 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -71,6 +71,7 @@ extern CAppModule _Module; #include #include +#include #pragma warning(disable: 4503) // disables 'name truncated' warnings From 0663089489112bd52e9dd280b2dcd33acf51f983 Mon Sep 17 00:00:00 2001 From: cbucher Date: Thu, 30 Sep 2010 10:50:28 +0200 Subject: [PATCH 042/207] UpdateLayout_ScrollToFit calculate a new scroll offset, when all tabs can be diplayed. This offset will be corrected later. The correct value is needed to calculate the right position for the close button. So UpdateScrollOverflowStatus is called to correct the close button position. --- Console/AeroTabCtrl.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Console/AeroTabCtrl.h b/Console/AeroTabCtrl.h index f41e900d..39afa381 100644 --- a/Console/AeroTabCtrl.h +++ b/Console/AeroTabCtrl.h @@ -340,7 +340,7 @@ class CAeroTabCtrlImpl : { int nImageHalfHeight = (ii.rcImage.bottom - ii.rcImage.top) / 2; - CIcon tabSmallIcon(m_imageList.ExtractIcon(nImageIndex)); + CIcon tabSmallIcon(m_imageList.ExtractIcon(nImageIndex)); if( !tabSmallIcon.IsNull() ) { WTL::CDCHandle dc(bufferedDC); @@ -348,7 +348,7 @@ class CAeroTabCtrlImpl : rcText.left, nIconVerticalCenter - nImageHalfHeight + m_nFontSizeTextTopOffset, tabSmallIcon.m_hIcon, 16, 16); - } + } } // Offset on the right of the image. @@ -576,7 +576,7 @@ class CAeroTabCtrlImpl : RECT rcItemDP = {0}; ::CopyRect(&rcItemDP, &rcItem); - ::OffsetRect(&rcItemDP, m_iScrollOffset, 0); + //::OffsetRect(&rcItemDP, m_iScrollOffset, 0); int nIconVerticalCenter; if (CTCS_BOTTOM == (this->GetStyle() & CTCS_BOTTOM)) @@ -642,6 +642,7 @@ class CAeroTabCtrlImpl : if( bSelected ) { UpdateLayout_CloseButton(rcItem); + ::OffsetRect(&m_rcCloseButton, m_iScrollOffset, 0); } rcItem.right += m_iCloseButtonWidth; @@ -812,8 +813,11 @@ class CAeroTabCtrlImpl : { m_iScrollOffset = (rcTabItemArea.right - xpos); } + this->UpdateScrollOverflowStatus(); dc.SelectFont(hOldFont); + + ::OffsetRect(&m_rcCloseButton, m_iScrollOffset, 0); } }; From 69194b5dd2336e1591911c19080c3f27bbfdffa2 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Fri, 24 Sep 2010 12:40:08 +0200 Subject: [PATCH 043/207] Updated help a bit --- help/console.hhc | 4 ++++ help/console.hhp | 1 + help/html/credentials.html | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 help/html/credentials.html diff --git a/help/console.hhc b/help/console.hhc index b66ab794..80f2d6d5 100644 --- a/help/console.hhc +++ b/help/console.hhc @@ -73,6 +73,10 @@ +

  • + + +
  • diff --git a/help/console.hhp b/help/console.hhp index 43231141..b33e0a57 100644 --- a/help/console.hhp +++ b/help/console.hhp @@ -33,6 +33,7 @@ html\tips_tricks.html html\bugs_limitations.html html\reporting_problems.html html\changelog.html +html\credentials.html [INFOTYPES] diff --git a/help/html/credentials.html b/help/html/credentials.html new file mode 100644 index 00000000..e266a2a8 --- /dev/null +++ b/help/html/credentials.html @@ -0,0 +1,33 @@ + + + + + Opening tabs as another user + + + + + +

    Opening tabs as another user

    + +

    + If you configured a tab to run a shell as a different user, you will be + asked for a username and password before opening a tab. To use a domain + account, enter your username in the form domain\username +

    + +

    + Running a shell as a different user has some limitations: +
    +

      +
    • User's HOME env. variable must be explicitly set
    • +
    • + If you're running 32-bit Console on 64-bit Windows and attempt to + run cmd.exe as a shell, a 64-bit cmd.exe will be started and crash. +
    • +
    +

    + + + + \ No newline at end of file From 381c1d274c997239b02ea15ee7dca5ea91a3d5f0 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Tue, 28 Sep 2010 18:36:27 +0200 Subject: [PATCH 044/207] A small repaint fix --- Console/ConsoleView.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index c484face..f11e3b77 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -783,16 +783,21 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* UpdateTitle(); // if the view is not visible, don't repaint - if (!m_bActive && textChanged) + if (!m_bActive) { - if ((!bResize) && + if + ( + textChanged && + !bResize && (g_settingsHandler->GetBehaviorSettings().tabHighlightSettings.dwFlashes > 0) && - (!m_bFlashTimerRunning)) + (!m_bFlashTimerRunning) + ) { m_dwFlashes = 0; m_bFlashTimerRunning = true; SetTimer(FLASH_TAB_TIMER, 500); } + return 0; } From 8cc77bbf0192fbe216b513fa0982f5eb56a575f1 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Wed, 29 Sep 2010 13:58:31 +0100 Subject: [PATCH 045/207] Expanded 'trim tab titles' options - you can now show characters at the end of the string --- Console/Console.rc | 315 +++++++++++++++--------------- Console/DlgSettingsAppearance.cpp | 6 + Console/DlgSettingsAppearance.h | 1 + Console/MainFrame.cpp | 58 +++--- Console/MainFrame.h | 1 + Console/SettingsHandler.cpp | 4 + Console/SettingsHandler.h | 1 + Console/resource.h | 3 + 8 files changed, 206 insertions(+), 183 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index b7060a7f..734e7503 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -108,118 +108,6 @@ END #endif // APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Toolbar -// - -IDR_MAINFRAME TOOLBAR 16, 16 -BEGIN - BUTTON ID_FILE_NEW_TAB - BUTTON ID_PREV_TAB - BUTTON ID_NEXT_TAB - SEPARATOR - BUTTON ID_EDIT_COPY - BUTTON ID_EDIT_PASTE - SEPARATOR - BUTTON ID_APP_ABOUT - BUTTON ID_HELP -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// -#ifdef _USE_AERO -IDR_MAINFRAME BITMAP "res\\toolbar_aero.bmp" -#else -IDR_MAINFRAME BITMAP "res\\Toolbar.bmp" -#endif - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDR_MAINFRAME MENU -BEGIN - POPUP "File" - BEGIN - MENUITEM "&New Tab", ID_FILE_NEW_TAB - MENUITEM "&Close Tab", ID_FILE_CLOSE_TAB - MENUITEM SEPARATOR - MENUITEM "E&xit", ID_APP_EXIT - END - POPUP "Edit" - BEGIN - MENUITEM "&Copy", ID_EDIT_COPY - MENUITEM "Cl&ear selection", 32791 - MENUITEM "&Paste", ID_EDIT_PASTE - MENUITEM SEPARATOR - MENUITEM "Stop Scr&olling", ID_EDIT_STOP_SCROLLING - MENUITEM SEPARATOR - MENUITEM "&Rename Tab", ID_EDIT_RENAME_TAB - MENUITEM SEPARATOR - MENUITEM "&Settings...", ID_EDIT_SETTINGS - END - POPUP "View" - BEGIN - MENUITEM "&Console Window", ID_VIEW_CONSOLE - MENUITEM SEPARATOR - MENUITEM "&Menu", ID_VIEW_MENU - MENUITEM "&Toolbar", ID_VIEW_TOOLBAR - MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR - MENUITEM "Ta&bs", ID_VIEW_TABS - END - POPUP "Help" - BEGIN - MENUITEM "&Help", ID_HELP - MENUITEM SEPARATOR - MENUITEM "&About Console...", ID_APP_ABOUT - END -END - -IDR_POPUP_MENU_TAB MENU -BEGIN - POPUP "_" - BEGIN - POPUP "&File" - BEGIN - MENUITEM "&New Tab", 32775 - MENUITEM "&Close Tab", 32779 - MENUITEM SEPARATOR - MENUITEM "E&xit", 57665 - END - POPUP "&Edit" - BEGIN - MENUITEM "&Copy", 57634 - MENUITEM "Cl&ear selection", 32791 - MENUITEM "&Paste", 57637 - MENUITEM SEPARATOR - MENUITEM "&Rename Tab", 32781 - MENUITEM SEPARATOR - MENUITEM "&Settings...", ID_EDIT_SETTINGS - END - POPUP "&View" - BEGIN - MENUITEM "&Console Window", 32777 - MENUITEM SEPARATOR - MENUITEM "&Menu", 32784 - MENUITEM "&Toolbar", 59392 - MENUITEM "&Status Bar", 59393 - MENUITEM "Ta&bs", 32789 - END - POPUP "&Help" - BEGIN - MENUITEM "&Help", 57670 - MENUITEM SEPARATOR - MENUITEM "&About Console...", 57664 - END - END -END - - ///////////////////////////////////////////////////////////////////////////// // // Dialog @@ -345,47 +233,50 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,30,100,10 CONTROL "S&how command",IDC_CHECK_SHOW_COMMAND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,40,65,10 CONTROL "Sho&w command in tabs",IDC_CHECK_SHOW_COMMAND_TABS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,50,89,10 - CONTROL "Trim tab titles",IDC_CHECK_TRIM_TAB_TITLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,103,50,59,10 - EDITTEXT IDC_TRIM_TAB_TITLES,162,48,31,14,ES_AUTOHSCROLL - CONTROL "",IDC_SPIN_TRIM_TAB_TITLES,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,178,35,11,14 - LTEXT "characters",IDC_STATIC_TRIM_CHARS,195,51,34,8 - LTEXT "I&con:",IDC_STATIC,10,71,18,8 - EDITTEXT IDC_WINDOW_ICON,33,68,165,14,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_BTN_BROWSE_ICON,200,68,16,14 - CONTROL "Use tab &icons",IDC_CHECK_USE_TAB_ICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,85,59,10 - GROUPBOX "Title && icon",IDC_STATIC,0,0,235,100 - LTEXT "Name:",IDC_STATIC,10,118,20,8 - EDITTEXT IDC_FONT,33,115,110,14,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "...",IDC_BTN_BROWSE_FONT,145,115,16,14 - LTEXT "Si&ze:",IDC_STATIC,168,118,16,8 - EDITTEXT IDC_FONT_SIZE,186,115,30,14,ES_AUTOHSCROLL - CONTROL "",IDC_SPIN_FONT_SIZE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,218,115,11,14 - CONTROL "&Bold",IDC_CHECK_BOLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,137,29,10 - CONTROL "It&alic",IDC_CHECK_ITALIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,47,137,31,10 - LTEXT "Smoothing:",IDC_STATIC,91,138,37,8 - COMBOBOX IDC_COMBO_SMOOTHING,130,136,65,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "C&ustom color:",IDC_CHECK_USE_COLOR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,154,56,10 - CONTROL "",IDC_FONT_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,69,152,16,14,WS_EX_DLGMODALFRAME - GROUPBOX "Font",IDC_STATIC,0,102,235,70 - CONTROL "Initial p&osition*",IDC_CHECK_POSITION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,189,60,10 - LTEXT "X:",IDC_STATIC,73,190,8,8 - EDITTEXT IDC_POS_X,83,187,37,14,ES_AUTOHSCROLL - CONTROL "",IDC_SPIN_X,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,107,177,11,14 - LTEXT "Y:",IDC_STATIC,126,190,8,8 - EDITTEXT IDC_POS_Y,136,187,37,14,ES_AUTOHSCROLL - CONTROL "",IDC_SPIN_Y,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,160,177,11,14 - CONTROL "Save on exit",IDC_CHECK_SAVE_POSITION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,179,189,52,10 - CONTROL "&Snap to desktop edges",IDC_CHECK_SNAP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,207,89,10 - LTEXT "&Distance:",IDC_STATIC,104,208,31,8 - EDITTEXT IDC_SNAP,136,205,37,14,ES_AUTOHSCROLL - CONTROL "",IDC_SPIN_SNAP,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,166,212,11,14 - LTEXT "pixels",IDC_STATIC,179,208,19,8 - LTEXT "Docking *:",IDC_STATIC,10,227,34,8 - COMBOBOX IDC_COMBO_DOCKING,45,225,55,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Z order:",IDC_STATIC,115,227,27,8 - COMBOBOX IDC_COMBO_ZORDER,144,225,65,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Position",IDC_STATIC,0,174,235,72 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,131,40,89,10 + CONTROL "Trim tab titles to",IDC_CHECK_TRIM_TAB_TITLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,50,64,10 + EDITTEXT IDC_TRIM_TAB_TITLES,19,63,31,14,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_TRIM_TAB_TITLES,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,8,63,11,14 + LTEXT "characters with",IDC_STATIC_TRIM_CHARS,53,66,50,8 + EDITTEXT IDC_TRIM_TAB_TITLES_RIGHT,105,63,31,14,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_TRIM_TAB_TITLES_RIGHT,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,199,63,11,14 + LTEXT "chars at the end",IDC_STATIC_TRIM_CHARS_RIGHT,139,66,54,8 + LTEXT "I&con:",IDC_STATIC,10,90,18,8 + EDITTEXT IDC_WINDOW_ICON,33,87,165,14,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_BTN_BROWSE_ICON,200,87,16,14 + CONTROL "Use tab &icons",IDC_CHECK_USE_TAB_ICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,33,104,59,10 + GROUPBOX "Title && icon",IDC_STATIC,0,0,235,120 + LTEXT "Name:",IDC_STATIC,10,137,20,8 + EDITTEXT IDC_FONT,33,134,110,14,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "...",IDC_BTN_BROWSE_FONT,145,134,16,14 + LTEXT "Si&ze:",IDC_STATIC,168,137,16,8 + EDITTEXT IDC_FONT_SIZE,186,134,30,14,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_FONT_SIZE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,218,134,11,14 + CONTROL "&Bold",IDC_CHECK_BOLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,156,29,10 + CONTROL "It&alic",IDC_CHECK_ITALIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,47,156,31,10 + LTEXT "Smoothing:",IDC_STATIC,91,157,37,8 + COMBOBOX IDC_COMBO_SMOOTHING,130,155,65,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "C&ustom color:",IDC_CHECK_USE_COLOR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,173,56,10 + CONTROL "",IDC_FONT_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,69,171,16,14,WS_EX_DLGMODALFRAME + GROUPBOX "Font",IDC_STATIC,0,121,235,70 + CONTROL "Initial p&osition*",IDC_CHECK_POSITION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,208,60,10 + LTEXT "X:",IDC_STATIC,73,209,8,8 + EDITTEXT IDC_POS_X,83,206,37,14,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_X,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,107,196,11,14 + LTEXT "Y:",IDC_STATIC,126,209,8,8 + EDITTEXT IDC_POS_Y,136,206,37,14,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_Y,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,160,196,11,14 + CONTROL "Save on exit",IDC_CHECK_SAVE_POSITION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,179,208,52,10 + CONTROL "&Snap to desktop edges",IDC_CHECK_SNAP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,226,89,10 + LTEXT "&Distance:",IDC_STATIC,104,227,31,8 + EDITTEXT IDC_SNAP,136,224,37,14,ES_AUTOHSCROLL + CONTROL "",IDC_SPIN_SNAP,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,166,231,11,14 + LTEXT "pixels",IDC_STATIC,179,227,19,8 + LTEXT "Docking *:",IDC_STATIC,10,246,34,8 + COMBOBOX IDC_COMBO_DOCKING,45,244,55,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Z order:",IDC_STATIC,115,246,27,8 + COMBOBOX IDC_COMBO_ZORDER,144,244,65,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Position",IDC_STATIC,0,193,235,72 END IDD_SETTINGS_HOTKEYS DIALOGEX 0, 0, 226, 254 @@ -632,9 +523,7 @@ BEGIN HORZGUIDE, 35 HORZGUIDE, 45 HORZGUIDE, 55 - HORZGUIDE, 75 - HORZGUIDE, 90 - HORZGUIDE, 100 + HORZGUIDE, 70 END IDD_SETTINGS_STYLES, DIALOG @@ -704,6 +593,119 @@ END #endif // APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Toolbar +// + +IDR_MAINFRAME TOOLBAR 16, 16 +BEGIN + BUTTON ID_FILE_NEW_TAB + BUTTON ID_PREV_TAB + BUTTON ID_NEXT_TAB + SEPARATOR + BUTTON ID_EDIT_COPY + BUTTON ID_EDIT_PASTE + SEPARATOR + BUTTON ID_APP_ABOUT + BUTTON ID_HELP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +#ifdef _USE_AERO +IDR_MAINFRAME BITMAP "res\\toolbar_aero.bmp" +#else +IDR_MAINFRAME BITMAP "res\\Toolbar.bmp" +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MAINFRAME MENU +BEGIN + POPUP "File" + BEGIN + MENUITEM "&New Tab", ID_FILE_NEW_TAB + MENUITEM "&Close Tab", ID_FILE_CLOSE_TAB + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_APP_EXIT + END + POPUP "Edit" + BEGIN + MENUITEM "&Copy", ID_EDIT_COPY + MENUITEM "Cl&ear selection", 32791 + MENUITEM "&Paste", ID_EDIT_PASTE + MENUITEM SEPARATOR + MENUITEM "Stop Scr&olling", ID_EDIT_STOP_SCROLLING + MENUITEM SEPARATOR + MENUITEM "&Rename Tab", ID_EDIT_RENAME_TAB + MENUITEM SEPARATOR + MENUITEM "&Settings...", ID_EDIT_SETTINGS + END + POPUP "View" + BEGIN + MENUITEM "&Console Window", ID_VIEW_CONSOLE + MENUITEM SEPARATOR + MENUITEM "&Menu", ID_VIEW_MENU + MENUITEM "&Toolbar", ID_VIEW_TOOLBAR + MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR + MENUITEM "Ta&bs", ID_VIEW_TABS + END + POPUP "Help" + BEGIN + MENUITEM "&Help", ID_HELP + MENUITEM SEPARATOR + MENUITEM "&About Console...", ID_APP_ABOUT + END +END + +IDR_POPUP_MENU_TAB MENU +BEGIN + POPUP "_" + BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New Tab", 32775 + MENUITEM "&Close Tab", 32779 + MENUITEM SEPARATOR + MENUITEM "E&xit", 57665 + END + POPUP "&Edit" + BEGIN + MENUITEM "&Copy", 57634 + MENUITEM "Cl&ear selection", 32791 + MENUITEM "&Paste", 57637 + MENUITEM SEPARATOR + MENUITEM "&Rename Tab", 32781 + MENUITEM SEPARATOR + MENUITEM "&Settings...", ID_EDIT_SETTINGS + END + POPUP "&View" + BEGIN + MENUITEM "&Console Window", 32777 + MENUITEM SEPARATOR + MENUITEM "&Menu", 32784 + MENUITEM "&Toolbar", 59392 + MENUITEM "&Status Bar", 59393 + MENUITEM "Ta&bs", 32789 + END + POPUP "&Help" + BEGIN + MENUITEM "&Help", 57670 + MENUITEM SEPARATOR + MENUITEM "&About Console...", 57664 + END + END +END + + ///////////////////////////////////////////////////////////////////////////// // // Version @@ -974,7 +976,6 @@ END // Generated from the TEXTINCLUDE 3 resource. // - ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/Console/DlgSettingsAppearance.cpp b/Console/DlgSettingsAppearance.cpp index 377ec12f..975413c1 100644 --- a/Console/DlgSettingsAppearance.cpp +++ b/Console/DlgSettingsAppearance.cpp @@ -306,7 +306,10 @@ void DlgSettingsAppearance::EnableControls() GetDlgItem(IDC_CHECK_SHOW_COMMAND_TABS).EnableWindow(FALSE); GetDlgItem(IDC_TRIM_TAB_TITLES).EnableWindow(FALSE); GetDlgItem(IDC_SPIN_TRIM_TAB_TITLES).EnableWindow(FALSE); + GetDlgItem(IDC_TRIM_TAB_TITLES_RIGHT).EnableWindow(FALSE); + GetDlgItem(IDC_SPIN_TRIM_TAB_TITLES_RIGHT).EnableWindow(FALSE); GetDlgItem(IDC_STATIC_TRIM_CHARS).EnableWindow(FALSE); + GetDlgItem(IDC_STATIC_TRIM_CHARS_RIGHT).EnableWindow(FALSE); GetDlgItem(IDC_WINDOW_ICON).EnableWindow(FALSE); GetDlgItem(IDC_BTN_BROWSE_ICON).EnableWindow(FALSE); GetDlgItem(IDC_FONT_COLOR).EnableWindow(FALSE); @@ -329,7 +332,10 @@ void DlgSettingsAppearance::EnableControls() { GetDlgItem(IDC_TRIM_TAB_TITLES).EnableWindow(); GetDlgItem(IDC_SPIN_TRIM_TAB_TITLES).EnableWindow(); + GetDlgItem(IDC_TRIM_TAB_TITLES_RIGHT).EnableWindow(); + GetDlgItem(IDC_SPIN_TRIM_TAB_TITLES_RIGHT).EnableWindow(); GetDlgItem(IDC_STATIC_TRIM_CHARS).EnableWindow(); + GetDlgItem(IDC_STATIC_TRIM_CHARS_RIGHT).EnableWindow(); } if (m_nUseTabIcon == 0) diff --git a/Console/DlgSettingsAppearance.h b/Console/DlgSettingsAppearance.h index a456ea84..31f9873c 100644 --- a/Console/DlgSettingsAppearance.h +++ b/Console/DlgSettingsAppearance.h @@ -28,6 +28,7 @@ class DlgSettingsAppearance DDX_CHECK(IDC_CHECK_SHOW_COMMAND_TABS, m_nShowCommandTabs) DDX_CHECK(IDC_CHECK_TRIM_TAB_TITLES, m_nTrimTabTitles) DDX_UINT(IDC_TRIM_TAB_TITLES, m_windowSettings.dwTrimTabTitles) + DDX_UINT(IDC_TRIM_TAB_TITLES_RIGHT, m_windowSettings.dwTrimTabTitlesRight) DDX_TEXT(IDC_WINDOW_ICON, m_strWindowIcon) DDX_CHECK(IDC_CHECK_USE_TAB_ICON, m_nUseTabIcon) DDX_TEXT(IDC_FONT, m_strFontName) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 0374b7ae..9862f8aa 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -895,14 +895,7 @@ LRESULT MainFrame::OnUpdateTitles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam* { CString strTabTitle(consoleView->GetTitle()); - // We always give the tool tip the complete, untrimmed text - UpdateTabToolTip(consoleView->m_hWnd, strTabTitle); - - if ((windowSettings.dwTrimTabTitles > 0) && (strTabTitle.GetLength() > static_cast(windowSettings.dwTrimTabTitles))) - { - strTabTitle = strTabTitle.Left(windowSettings.dwTrimTabTitles) + CString(L"..."); - } - UpdateTabText(consoleView->m_hWnd, strTabTitle); + UpdateTabTitle(consoleView, strTabTitle); if ((m_strCmdLineWindowTitle.GetLength() == 0) && (windowSettings.bUseTabTitles) && @@ -942,14 +935,7 @@ LRESULT MainFrame::OnUpdateTitles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam* if (windowSettings.bShowCommandInTabs) strTabTitle += strCommandText; - // We always give the tool tip the complete, untrimmed text - UpdateTabToolTip(consoleView->m_hWnd, strTabTitle); - - if ((windowSettings.dwTrimTabTitles > 0) && (strTabTitle.GetLength() > static_cast(windowSettings.dwTrimTabTitles))) - { - strTabTitle = strTabTitle.Left(windowSettings.dwTrimTabTitles) + CString(L"..."); - } - UpdateTabText(consoleView->m_hWnd, strTabTitle); + UpdateTabTitle(consoleView, strTabTitle); } return 0; @@ -1359,22 +1345,15 @@ LRESULT MainFrame::OnEditRenameTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hW if (dlg.DoModal() == IDOK) { - WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; m_activeView->SetTitle(dlg.m_strTabName); - CString strTabTitle(dlg.m_strTabName); + WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; + CString strTabTitle(dlg.m_strTabName); if (windowSettings.bShowCommandInTabs) strTabTitle += m_activeView->GetConsoleCommand(); - // We always give the tool tip the complete, untrimmed text - UpdateTabToolTip(*m_activeView, strTabTitle); - - if ((windowSettings.dwTrimTabTitles > 0) && (strTabTitle.GetLength() > static_cast(windowSettings.dwTrimTabTitles))) - { - strTabTitle = strTabTitle.Left(windowSettings.dwTrimTabTitles) + CString(L"..."); - } - UpdateTabText(*m_activeView, strTabTitle); + UpdateTabTitle(m_activeView, strTabTitle); if (windowSettings.bUseTabTitles) SetWindowText(m_activeView->GetTitle()); } @@ -1759,6 +1738,33 @@ void MainFrame::CloseTab(HWND hwndConsoleView) ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +void MainFrame::UpdateTabTitle(const shared_ptr& consoleView, CString& strTabTitle) +{ + // we always set the tool tip text to the complete, untrimmed title + UpdateTabToolTip(*consoleView, strTabTitle); + + WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; + + if + ( + (windowSettings.dwTrimTabTitles > 0) + && + (windowSettings.dwTrimTabTitles > windowSettings.dwTrimTabTitlesRight) + && + (strTabTitle.GetLength() > static_cast(windowSettings.dwTrimTabTitles)) + ) + { + strTabTitle = strTabTitle.Left(windowSettings.dwTrimTabTitles - windowSettings.dwTrimTabTitlesRight) + CString(L"...") + strTabTitle.Right(windowSettings.dwTrimTabTitlesRight); + } + + UpdateTabText(*consoleView, strTabTitle); +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// void MainFrame::UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu) diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 613425d2..9234f8e4 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -203,6 +203,7 @@ class MainFrame void CloseTab(CTabViewTabItem* pTabItem); void CloseTab(HWND hwndConsoleView); + void UpdateTabTitle(const shared_ptr& consoleView, CString& strTabTitle); void UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu); void UpdateStatusBar(); void SetWindowStyles(); diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index 3f4ae113..9a510473 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -282,6 +282,7 @@ WindowSettings::WindowSettings() , bShowCommandInTabs(true) , bUseTabTitles(false) , dwTrimTabTitles(0) +, dwTrimTabTitlesRight(0) { } @@ -304,6 +305,7 @@ bool WindowSettings::Load(const CComPtr& pSettingsRoot) XmlHelper::GetAttribute(pWindowElement, CComBSTR(L"show_cmd_tabs"), bShowCommandInTabs, true); XmlHelper::GetAttribute(pWindowElement, CComBSTR(L"use_tab_title"), bUseTabTitles, false); XmlHelper::GetAttribute(pWindowElement, CComBSTR(L"trim_tab_titles"), dwTrimTabTitles, 0); + XmlHelper::GetAttribute(pWindowElement, CComBSTR(L"trim_tab_titles_right"), dwTrimTabTitlesRight, 0); return true; } @@ -327,6 +329,7 @@ bool WindowSettings::Save(const CComPtr& pSettingsRoot) XmlHelper::SetAttribute(pWindowElement, CComBSTR(L"show_cmd_tabs"), bShowCommandInTabs); XmlHelper::SetAttribute(pWindowElement, CComBSTR(L"use_tab_title"), bUseTabTitles); XmlHelper::SetAttribute(pWindowElement, CComBSTR(L"trim_tab_titles"), dwTrimTabTitles); + XmlHelper::SetAttribute(pWindowElement, CComBSTR(L"trim_tab_titles_right"), dwTrimTabTitlesRight); return true; } @@ -346,6 +349,7 @@ WindowSettings& WindowSettings::operator=(const WindowSettings& other) bShowCommandInTabs = other.bShowCommandInTabs; bUseTabTitles = other.bUseTabTitles; dwTrimTabTitles = other.dwTrimTabTitles; + dwTrimTabTitlesRight= other.dwTrimTabTitlesRight; return *this; } diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index 718a81ad..0b519964 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -115,6 +115,7 @@ struct WindowSettings : public SettingsBase bool bShowCommandInTabs; bool bUseTabTitles; DWORD dwTrimTabTitles; + DWORD dwTrimTabTitlesRight; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/resource.h b/Console/resource.h index 41ada49f..16e365e1 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -132,6 +132,7 @@ #define IDC_RADIO_Z_REGULAR 1100 #define IDC_TRIM_TAB_TITLES 1101 #define IDC_RADIO_Z_BOTTOM 1102 +#define IDC_TRIM_TAB_TITLES_RIGHT 1102 #define IDC_RADIO_Z_ONTOP 1103 #define IDC_SNAP 1104 #define IDC_CHECK_POSITION 1105 @@ -149,6 +150,7 @@ #define IDC_SPIN_Y2 1116 #define IDC_SPIN_TRIM_TAB_TITLES 1116 #define IDC_TAB_TITLE 1117 +#define IDC_SPIN_TRIM_TAB_TITLES_RIGHT 1117 #define IDC_TAB_ICON 1118 #define IDC_RADIO_Z_DESKTOP 1118 #define IDC_TAB_SHELL 1119 @@ -219,6 +221,7 @@ #define IDC_TAB_USER 1174 #define IDC_USER 1175 #define IDC_PASSWORD 1176 +#define IDC_STATIC_TRIM_CHARS_RIGHT 1176 #define IDC_APPTEXT 1177 #define IDC_STATIC_USER 1177 #define IDC_APPICON 1178 From a52850a377729c6baee5f86062d9840cbc03966a Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Wed, 29 Sep 2010 14:59:35 +0200 Subject: [PATCH 046/207] Updated devel_changes.txt --- devel_changes.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/devel_changes.txt b/devel_changes.txt index f26c0abf..5ed07d89 100644 --- a/devel_changes.txt +++ b/devel_changes.txt @@ -23,6 +23,10 @@ Build 147 code still hasn't been tested with Vista/Win7 UAC, but it does work for shell processes started as another user, so we'll have that feature in Console soon as well. +- tabs can now be opened as a different user + +- expanded 'trim tab titles' options - you can now show characters at the end of the string + Build 146 ========= From 3b2ff97fce32a0363360453b8b015d51677a270d Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Wed, 29 Sep 2010 15:10:13 +0200 Subject: [PATCH 047/207] Improved command text resolution for tab titles. --- Console/ConsoleView.cpp | 11 ++++++++++- devel_changes.txt | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index f11e3b77..d1580449 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -1178,7 +1178,16 @@ CString ConsoleView::GetConsoleCommand() if (nPos == -1) { - return CString(L""); + nPos = strConsoleTitle.Find(L"Console2 command window"); + + if (nPos == -1) + { + return CString(L" - ") + strConsoleTitle; + } + else + { + return CString(); + } } else { diff --git a/devel_changes.txt b/devel_changes.txt index 5ed07d89..cacbd231 100644 --- a/devel_changes.txt +++ b/devel_changes.txt @@ -27,6 +27,8 @@ Build 147 - expanded 'trim tab titles' options - you can now show characters at the end of the string +- improved command text resolution for tab titles. + Build 146 ========= From 18e1fe28acd86b4b72901ab257a271dfe848525c Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Thu, 30 Sep 2010 17:47:39 +0200 Subject: [PATCH 048/207] Fixed invalid window position on Windows unlock --- Console/ConsoleView.cpp | 2 +- Console/MainFrame.cpp | 5 ++++- ConsoleHook/stdafx.h | 2 +- ConsoleWow/targetver.h | 2 +- devel_changes.txt | 4 +++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index d1580449..49e35593 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -313,7 +313,7 @@ LRESULT ConsoleView::OnConsoleFwdMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BO if (!TranslateKeyDown(uMsg, wParam, lParam)) { - TRACE(L"Msg: 0x%04X, wParam: 0x%08X, lParam: 0x%08X\n", uMsg, wParam, lParam); +// TRACE(L"Msg: 0x%04X, wParam: 0x%08X, lParam: 0x%08X\n", uMsg, wParam, lParam); ::PostMessage(m_consoleHandler.GetConsoleParams()->hwndConsoleWindow, uMsg, wParam, lParam); } diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 9862f8aa..b21b8526 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -680,7 +680,10 @@ LRESULT MainFrame::OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM CPoint pointCursor; // we'll snap Console window to the desktop edges - ::GetCursorPos(&pointCursor); + + // WM_WINDOWPOSCHANGING will be called when locking a computer + // GetCursorPos will fail in that case; in that case we return and prevent invalid window position after unlock + if (!::GetCursorPos(&pointCursor)) return 0; GetWindowRect(&rectWindow); Helpers::GetDesktopRect(pointCursor, rectDesktop); Helpers::GetMonitorRect(m_hWnd, rectMonitor); diff --git a/ConsoleHook/stdafx.h b/ConsoleHook/stdafx.h index daf14394..19239036 100644 --- a/ConsoleHook/stdafx.h +++ b/ConsoleHook/stdafx.h @@ -5,7 +5,7 @@ #pragma once -#define _WIN32_WINNT 0x0500 +#define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers ////////////////////////////////////////////////////////////////////////////// diff --git a/ConsoleWow/targetver.h b/ConsoleWow/targetver.h index 6fe8eb79..7021c2a5 100644 --- a/ConsoleWow/targetver.h +++ b/ConsoleWow/targetver.h @@ -8,6 +8,6 @@ // Modify the following defines if you have to target a platform prior to the ones specified below. // Refer to MSDN for the latest info on corresponding values for different platforms. #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. -#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif diff --git a/devel_changes.txt b/devel_changes.txt index cacbd231..b360a906 100644 --- a/devel_changes.txt +++ b/devel_changes.txt @@ -27,7 +27,9 @@ Build 147 - expanded 'trim tab titles' options - you can now show characters at the end of the string -- improved command text resolution for tab titles. +- improved command text resolution for tab titles + +- fixed invalid window position after Windows unlock (BR#2912069) Build 146 From 1b6987cfba005e24eece8d796d0cf87b7efe6c0d Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 2 Oct 2010 11:26:41 +0200 Subject: [PATCH 049/207] silent warnings cleanup code (remove animation) --- Console/AeroTabCtrl.h | 10 +- Console/AnimationWindow.cpp | 438 ------------------------------------ Console/AnimationWindow.h | 173 -------------- Console/Console.cpp | 2 +- Console/Console.vcproj | 8 - Console/ConsoleHandler.cpp | 2 +- Console/Cursors.cpp | 2 +- Console/MainFrame.cpp | 64 +----- Console/MainFrame.h | 3 - Console/SettingsHandler.cpp | 74 ------ Console/SettingsHandler.h | 46 ---- 11 files changed, 12 insertions(+), 810 deletions(-) delete mode 100644 Console/AnimationWindow.cpp delete mode 100644 Console/AnimationWindow.h diff --git a/Console/AeroTabCtrl.h b/Console/AeroTabCtrl.h index 39afa381..0585c8e4 100644 --- a/Console/AeroTabCtrl.h +++ b/Console/AeroTabCtrl.h @@ -12,8 +12,8 @@ class CAeroTabCtrlImpl : signed char m_iLeftSpacing; signed char m_iTopMargin; signed char m_iRadius; - signed char m_iCloseButtonWidth; - signed char m_iCloseButtonHeight; + signed long m_iCloseButtonWidth; + signed long m_iCloseButtonHeight; // Constructor public: @@ -237,11 +237,11 @@ class CAeroTabCtrlImpl : } } - void DrawItem_TabInactive(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw, RECT& rcTab) + void DrawItem_TabInactive(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW /*lpNMCustomDraw*/, RECT& /*rcTab*/) { } - void DrawItem_TabSelected(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW lpNMCustomDraw, RECT& rcTab) + void DrawItem_TabSelected(DWORD /*dwStyle*/, LPNMCTCCUSTOMDRAW /*lpNMCustomDraw*/, RECT& /*rcTab*/) { } @@ -475,7 +475,7 @@ class CAeroTabCtrlImpl : EndBufferedPaint(pb, TRUE); } - void CalcSize_CloseButton(LPRECT prcTabItemArea) + void CalcSize_CloseButton(LPRECT /*prcTabItemArea*/) { DWORD dwStyle = this->GetStyle(); diff --git a/Console/AnimationWindow.cpp b/Console/AnimationWindow.cpp deleted file mode 100644 index 4831b165..00000000 --- a/Console/AnimationWindow.cpp +++ /dev/null @@ -1,438 +0,0 @@ -#include "stdafx.h" - -#include "AnimationWindow.h" - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -// Constructor - -AnimationWindow::AnimationWindow(const AnimationWindowOptions& windowOptions) -: m_windowOptions(windowOptions) -, m_nIterations(0) -{ -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -// Overrides - -////////////////////////////////////////////////////////////////////////////// - -BOOL AnimationWindow::PreTranslateMessage(MSG* pMsg) -{ - pMsg; - return FALSE; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -void AnimationWindow::OnFinalMessage(HWND /*hWnd*/) -{ -/* - // find the window pair - AnimationWindowMap& AnimationWindowMap = GetAnimationWindowMap(); - AnimationWindowMap::iterator it = AnimationWindowMap.find(m_windowOptions.originalWnd); - - if (it != AnimationWindowMap.end()) - { - if (m_windowOptions.originalWnd.IsWindow()) - { - // if needed, remove topmost attribute - if (!m_bOrigWndTopmost) - { - m_windowOptions.originalWnd.SetWindowPos(HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); - } - - // show the window - if ((m_origWindowPlacement.showCmd == SW_SHOWNORMAL) && !m_windowOptions.bRestoreOriginalPosition) - { - ::SetWindowPos(it->first, HWND_TOP, m_rectWindow.left, m_rectWindow.top, 0, 0, SWP_NOSIZE); - } - else - { - ::SetWindowPos(it->first, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); - } - ::ShowWindow(it->first, SW_SHOW); - ::SetForegroundWindow(it->first); - } - - if (m_bRemoveFromMap) AnimationWindowMap.erase(it); - } -*/ -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -// Operations - -HWND AnimationWindow::Create() -{ - // Call parent Create - return CWindowImpl< - AnimationWindow, - CWindow, - CWinTraits >::Create( - NULL, - m_rectWindow); -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -void AnimationWindow::CloseWindow() -{ - DestroyWindow(); -// SendMessage(WM_CLOSE); -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -void AnimationWindow::SA() -{ - TRACE(L"AnimationWindow SA\n"); - - // set window check timer - SetTimer(TIMER_ANIMATE_WINDOW, 200); - m_nIterations = 0; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -void AnimationWindow::HA() -{ - TRACE(L"AnimationWindow HA\n"); - - KillTimer(TIMER_ANIMATE_WINDOW); - m_windowOptions.originalWnd.ShowWindow(SW_SHOW); - CloseWindow(); -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -// Message handlers - -////////////////////////////////////////////////////////////////////////////// - -LRESULT AnimationWindow::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) -{ -/* - // create background DC - m_dcWindow.CreateCompatibleDC(GetDC()); - - // create thumbnail DC - m_dcThumbnail.CreateCompatibleDC(GetDC()); - - // get original window's placement info - ::ZeroMemory(&m_origWindowPlacement, sizeof(WINDOWPLACEMENT)); - m_origWindowPlacement.length = sizeof(WINDOWPLACEMENT); - m_windowOptions.originalWnd.GetWindowPlacement(&m_origWindowPlacement); - - // set layered attribute for original window if needed - long lOrigWndExStyle = m_windowOptions.originalWnd.GetWindowLong(GWL_EXSTYLE); - - if ((lOrigWndExStyle & WS_EX_TOPMOST) != WS_EX_TOPMOST) - { - m_windowOptions.originalWnd.SetWindowPos(HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); - - m_windowOptions.originalWnd.RedrawWindow( - NULL, - NULL, - RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN); - } - else - { - m_bOrigWndTopmost = true; - } - - // now, set rectangles - CRect rectOrigWnd; - - m_windowOptions.originalWnd.GetWindowRect(&rectOrigWnd); - - m_rectClient.left = 0; - m_rectClient.top = 0; - - if (rectOrigWnd.Width() > rectOrigWnd.Height()) - { - m_rectClient.right = m_windowOptions.nWindowSize; - m_rectClient.bottom = m_windowOptions.nWindowSize * rectOrigWnd.Height() / rectOrigWnd.Width(); - } - else - { - m_rectClient.bottom = m_windowOptions.nWindowSize; - m_rectClient.right = m_windowOptions.nWindowSize * rectOrigWnd.Width() / rectOrigWnd.Height(); - } - - m_rectWindow = m_rectClient; - - // if we're drawing border, increase window size - if (m_windowOptions.bDrawBorder) - { - m_rectWindow.right += 2; - m_rectWindow.bottom += 2; - } - - m_rectWindow.OffsetRect(rectOrigWnd.left, rectOrigWnd.top); - - // create offscreen bitmap and select it into HDC - m_bmpWindow.CreateCompatibleBitmap(GetDC(), m_rectClient.Width(), m_rectClient.Height()); - m_dcWindow.SelectBitmap(m_bmpWindow); - - // create thumbnail bitmap - m_bmpThumbnail.CreateCompatibleBitmap(GetDC(), m_rectClient.Width(), m_rectClient.Height()); - m_dcThumbnail.SelectBitmap(m_bmpThumbnail); - - // set window border - if (m_windowOptions.bDrawBorder) - { - SetWindowLong( - GWL_STYLE, - GetWindowLong(GWL_STYLE) | WS_BORDER); - } - - // set window size and position - SetWindowPos( - m_windowOptions.hwndPosition, - m_rectWindow.left, - m_rectWindow.top, - m_rectWindow.Width(), - m_rectWindow.Height(), - 0); - - UpdateThumbnail(rectOrigWnd); - - // set window opacity - if (m_windowOptions.byOpacity < 255) - { - SetWindowLong( - GWL_EXSTYLE, - GetWindowLong(GWL_EXSTYLE) | WS_EX_LAYERED); - - ::SetLayeredWindowAttributes( - m_hWnd, - 0, - m_windowOptions.byOpacity, - LWA_ALPHA); - } - - // set window check timer - SetTimer(TIMER_WINDOW_CHECK, 500); - - SetZOrderCheck(); - - // finally, show the window - ShowWindow(SW_SHOW); -*/ - TRACE(L"AnimationWindow OnCreate\n"); - - m_rectWindow.left = 100; - m_rectWindow.top = 100; - m_rectWindow.right = 200; - m_rectWindow.bottom = 200; - - // set window size and position - SetWindowPos( - HWND_TOPMOST, - m_rectWindow.left, - m_rectWindow.top, - m_rectWindow.Width(), - m_rectWindow.Height(), - 0); - - // finally, show the window - ShowWindow(SW_SHOW); - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -LRESULT AnimationWindow::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) -{ - TRACE(L"AnimationWindow OnClose\n"); - - DestroyWindow(); -// bHandled = FALSE; - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -LRESULT AnimationWindow::OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) -{ - // don't do anything here, prevents flicker - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -LRESULT AnimationWindow::OnNcPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) -{ -/* - HDC hdcNc; - // 0x10000 is an undocumented flag need for this to work (get a window DC in WM_NCPAINT handler) - hdcNc = GetDCEx((HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN|0x10000); - - // draw border - RECT rect; - GetWindowRect(&rect); - ::OffsetRect(&rect, -rect.left, -rect.top); - ::FrameRect(hdcNc, &rect, m_brushBorder); - - ReleaseDC(hdcNc); -*/ - return 0; -}; - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -LRESULT AnimationWindow::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) -{ - TRACE(L"AnimationWindow OnPaint\n"); - - CPaintDC dc(m_hWnd); - - CBrush brush(::CreateSolidBrush(RGB(0, 0, 0))); - - dc.FillRect(&m_rectWindow, brush); -/* - CPaintDC dc(m_hWnd); - CRect rect; - - GetClientRect(&rect); - - // draw thumbnail - m_dcWindow.BitBlt( - 0, - 0, - m_rectClient.Width(), - m_rectClient.Height(), - m_dcThumbnail, - 0, - 0, - SRCCOPY); - - dc.BitBlt( - 0, - 0, - rect.right, - rect.bottom, - m_dcWindow, - 0, - 0, - SRCCOPY); -*/ - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -LRESULT AnimationWindow::OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) -{ - TRACE(L"AnimationWindow OnTimer\n"); - - if (wParam == TIMER_ANIMATE_WINDOW) - { - ++m_nIterations; - - if (m_nIterations == 10) - { - // TODO: implement here - - m_windowOptions.originalWnd.ShowWindow(SW_HIDE); - - KillTimer(TIMER_ANIMATE_WINDOW); - } - - Invalidate(); - } -/* - if (wParam == TIMER_ANIMATE_WINDOW) - { - if (!m_windowOptions.originalWnd.IsWindow()) CloseWindow(); - } -*/ - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -// Private operations - -////////////////////////////////////////////////////////////////////////////// - -void AnimationWindow::UpdateThumbnail(const CRect& rectOrigWnd) -{ -/* - m_dcThumbnail.SetStretchBltMode(HALFTONE); - - CDC dcOriginalWindow(::GetDCEx(m_windowOptions.originalWnd, NULL, DCX_WINDOW)); - m_dcThumbnail.StretchBlt( - 0, - 0, - m_rectClient.Width(), - m_rectClient.Height(), - dcOriginalWindow, - 0, - 0, - rectOrigWnd.Width(), - rectOrigWnd.Height(), - SRCCOPY); -*/ -} - -////////////////////////////////////////////////////////////////////////////// - diff --git a/Console/AnimationWindow.h b/Console/AnimationWindow.h deleted file mode 100644 index 83c8dc2c..00000000 --- a/Console/AnimationWindow.h +++ /dev/null @@ -1,173 +0,0 @@ -#pragma once - -#include "resource.h" - -////////////////////////////////////////////////////////////////////////////// - -#define TIMER_ANIMATE_WINDOW 42 - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -/** - * - * @struct AnimationWindowOptions - * - * @brief Struct used to store animation window options. - * -**/ -////////////////////////////////////////////////////////////////////////////// -struct AnimationWindowOptions -{ - /// Default constructor. - AnimationWindowOptions(HWND hwndOriginalWnd) - : originalWnd(hwndOriginalWnd) - {} - - /// Copy constructor. - AnimationWindowOptions(const AnimationWindowOptions& windowData) - : originalWnd(windowData.originalWnd) - { - } - - /// Original window handle. - CWindow originalWnd; -}; - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -/** - * - * @class AnimationWindow - * - * @brief Animation window class - * - * Animation window class. - * -**/ -////////////////////////////////////////////////////////////////////////////// -class AnimationWindow : public CWindowImpl > -{ - - /////////////// - // Constructor - /////////////// - public: - DECLARE_WND_CLASS_EX(L"Console animation window", CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS, COLOR_WINDOW) - - /// Constructor - AnimationWindow(const AnimationWindowOptions& windowOptions); - - - ///////////// - // Overrides - ///////////// - public: - virtual BOOL PreTranslateMessage(MSG* pMsg); - virtual void OnFinalMessage(HWND /*hWnd*/); - - - ////////////// - // Operations - ////////////// - public: - /// Creates a new popup window. - HWND Create(); - /// Closes the window. - void CloseWindow(); - - void SA(); - void HA(); - - - //////////////////// - // Message handlers - //////////////////// - public: - - BEGIN_MSG_MAP(AnimationWindow) - MESSAGE_HANDLER(WM_CREATE, OnCreate) - MESSAGE_HANDLER(WM_CLOSE, OnClose) - MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) - MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) - MESSAGE_HANDLER(WM_PAINT, OnPaint) - MESSAGE_HANDLER(WM_TIMER, OnTimer) - END_MSG_MAP() - - // Handler prototypes (uncomment arguments if needed): -// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) -// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) -// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) - - /// WM_CREATE handler - LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); - /// WM_CLOSE handler - LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); - - /// WM_ERASEBKGND handler. Overriden to NOOP. - LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); - /// WM_NCPAINT handler. Paints window border. - LRESULT OnNcPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled); - /// WM_PAINT handler. Paints window client area. - LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); - - /// WM_TIMER handler. Closes the window. - LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/); - - /// Handles restore window command - LRESULT OnRestoreWindow(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); - /// Handles set Z-order commands - LRESULT OnSetZOrder(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); - - - ////////////////////// - // Private operations - ////////////////////// - private: - void UpdateThumbnail(const CRect& rectOrigWnd); - - ///////////// - // Variables - ///////////// - private: - - /// Window options - AnimationWindowOptions m_windowOptions; - - /// Original window's placement flags - WINDOWPLACEMENT m_origWindowPlacement; - - /// Set to true if original window is layered - bool m_bOrigWndTopmost; - - /// Window rectangle. - CRect m_rectWindow; - - /// Client rectangle - CRect m_rectClient; - - /// Window client area HDC. - CDC m_dcWindow; - - /// Window client area bitmap. - CBitmap m_bmpWindow; - - /// Thumbnail DC - CDC m_dcThumbnail; - /// Thumbnail bitmap - CBitmap m_bmpThumbnail; - - int m_nIterations; -}; - -////////////////////////////////////////////////////////////////////////////// diff --git a/Console/Console.cpp b/Console/Console.cpp index f280a0b4..b05dcce9 100644 --- a/Console/Console.cpp +++ b/Console/Console.cpp @@ -69,7 +69,7 @@ void ParseCommandLine vector& startupDirs, vector& startupCmds, int& nMultiStartSleep, - wstring& strDbgCmdLine + wstring& /*strDbgCmdLine*/ ) { int argc = 0; diff --git a/Console/Console.vcproj b/Console/Console.vcproj index 0f3a0890..95aa9901 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -570,10 +570,6 @@ RelativePath=".\AboutDlg.cpp" > - - @@ -727,10 +723,6 @@ RelativePath=".\AeroTabCtrl.h" > - - diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 0ac94918..f782ddb6 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -83,7 +83,7 @@ bool ConsoleHandler::StartShellProcess const wstring& strConsoleTitle, DWORD dwStartupRows, DWORD dwStartupColumns, - bool bDebugFlag + bool /*bDebugFlag*/ ) { wstring strUsername(strUser); diff --git a/Console/Cursors.cpp b/Console/Cursors.cpp index 5784a717..1534d60d 100644 --- a/Console/Cursors.cpp +++ b/Console/Cursors.cpp @@ -1064,7 +1064,7 @@ FadeBlockCursor::~FadeBlockCursor() ////////////////////////////////////////////////////////////////////////////// -void FadeBlockCursor::Draw(bool bActive /* = true */) +void FadeBlockCursor::Draw(bool /*bActive*/ /* = true */) { m_dcCursor.FillRect(&m_rectCursor, m_paintBrush); /* diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index b21b8526..a78e890a 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -54,7 +54,6 @@ MainFrame::MainFrame , m_dwResizeWindowEdge(WMSZ_BOTTOM) , m_bRestoringWindow(false) , m_rectRestoredWnd(0, 0, 0, 0) -, m_animationWindow() , m_iSelectionSize(0) { m_Margins.cxLeftWidth = 0; @@ -316,7 +315,7 @@ LRESULT MainFrame::OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPara ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) +LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if( m_views.size() > 1 && (::MessageBox(m_hWnd, L"Are you sure you want close all tabs ?", L"Close", MB_OKCANCEL | MB_ICONQUESTION) == IDCANCEL) ) return 0; @@ -402,61 +401,6 @@ LRESULT MainFrame::OnActivateApp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/ return 0; } -// if (g_settingsHandler->GetBehaviorSettings().animateSettings.dwType != animTypeNone) -// { -/* - DWORD dwFlags = (g_settingsHandler->GetBehaviorSettings().animateSettings.dwType == animTypeBlend) ? AW_BLEND : AW_SLIDE; - - switch (g_settingsHandler->GetBehaviorSettings().animateSettings.dwType) - { - case animTypeSlide : - { - dwFlags = AW_SLIDE; - - switch (g_settingsHandler->GetBehaviorSettings().animateSettings.dwHorzDirection) - { - case animDirPositive : dwFlags |= AW_HOR_POSITIVE; break; - case animDirNegative : dwFlags |= AW_HOR_NEGATIVE; break; - } - - switch (g_settingsHandler->GetBehaviorSettings().animateSettings.dwVertDirection) - { - case animDirPositive : dwFlags |= AW_VER_POSITIVE; break; - case animDirNegative : dwFlags |= AW_VER_NEGATIVE; break; - } - - break; - } - - case animTypeZoom : dwFlags = AW_CENTER; break; - case animTypeBlend : dwFlags = AW_BLEND; break; - } - - if (!bActivating) dwFlags |= AW_HIDE; - - ::AnimateWindow(m_hWnd, g_settingsHandler->GetBehaviorSettings().animateSettings.dwTime, dwFlags); -*/ -/* - if (bActivating) - { - TRACE(L"Activating\n"); - m_animationWindow->HA(); - m_animationWindow.reset(); - } - else - { - TRACE(L"Deactivating\n"); - AnimationWindowOptions opt(m_hWnd); - m_animationWindow.reset(new AnimationWindow(opt)); - - m_animationWindow->Create(); - m_animationWindow->SA(); - } -*/ - -// if (bActivating) ::RedrawWindow(m_hWnd, NULL, NULL, RDW_ERASE|RDW_INVALIDATE|RDW_ERASENOW|RDW_UPDATENOW|RDW_ALLCHILDREN); -// } - bHandled = FALSE; return 0; } @@ -499,7 +443,7 @@ LRESULT MainFrame::OnHotKey(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOO ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnSysKeydown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +LRESULT MainFrame::OnSysKeydown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { /* if ((wParam == VK_SPACE) && (lParam & (0x1 << 29))) @@ -575,7 +519,7 @@ LRESULT MainFrame::OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lPar ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +LRESULT MainFrame::OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { // Start timer that will force a call to ResizeWindow (called from WM_EXITSIZEMOVE handler // when the Console window is resized using a mouse) @@ -798,7 +742,7 @@ LRESULT MainFrame::OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnExitSizeMove(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) +LRESULT MainFrame::OnExitSizeMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { ResizeWindow(); return 0; diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 9234f8e4..d44f8b44 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -1,6 +1,5 @@ #pragma once -#include "AnimationWindow.h" ////////////////////////////////////////////////////////////////////////////// @@ -278,8 +277,6 @@ class MainFrame CDC m_dcOffscreen; CDC m_dcText; - shared_ptr m_animationWindow; - MARGINS m_Margins; }; diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index 9a510473..16427d16 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -956,77 +956,6 @@ TabHighlightSettings& TabHighlightSettings::operator=(const TabHighlightSettings ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -AnimateSettings::AnimateSettings() -: dwType(animTypeNone) -, dwHorzDirection(animDirNone) -, dwVertDirection(animDirNone) -, dwTime(0) -{ -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -bool AnimateSettings::Load(const CComPtr& pSettingsRoot) -{ - CComPtr pAnimateElement; - - if (FAILED(XmlHelper::GetDomElement(pSettingsRoot, CComBSTR(L"behavior/animate"), pAnimateElement))) return false; - - XmlHelper::GetAttribute(pAnimateElement, CComBSTR(L"type"), dwType, animTypeNone); - XmlHelper::GetAttribute(pAnimateElement, CComBSTR(L"horz_direction"), dwHorzDirection, animDirNone); - XmlHelper::GetAttribute(pAnimateElement, CComBSTR(L"vert_direction"), dwVertDirection, animDirNone); - XmlHelper::GetAttribute(pAnimateElement, CComBSTR(L"time"), dwTime, 200); - - return true; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -bool AnimateSettings::Save(const CComPtr& pSettingsRoot) -{ - CComPtr pAnimateElement; - - if (FAILED(XmlHelper::GetDomElement(pSettingsRoot, CComBSTR(L"behavior/animate"), pAnimateElement))) return false; - - XmlHelper::SetAttribute(pAnimateElement, CComBSTR(L"type"), dwType); - XmlHelper::SetAttribute(pAnimateElement, CComBSTR(L"horz_direction"), dwHorzDirection); - XmlHelper::SetAttribute(pAnimateElement, CComBSTR(L"vert_direction"), dwVertDirection); - XmlHelper::SetAttribute(pAnimateElement, CComBSTR(L"time"), dwTime); - - return true; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -AnimateSettings& AnimateSettings::operator=(const AnimateSettings& other) -{ - dwType = other.dwType; - dwHorzDirection = other.dwHorzDirection; - dwVertDirection = other.dwVertDirection; - dwTime = other.dwTime; - - return *this; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// BehaviorSettings::BehaviorSettings() @@ -1043,7 +972,6 @@ bool BehaviorSettings::Load(const CComPtr& pSettingsRoot) copyPasteSettings.Load(pSettingsRoot); scrollSettings.Load(pSettingsRoot); tabHighlightSettings.Load(pSettingsRoot); -// animateSettings.Load(pSettingsRoot); return true; } @@ -1057,7 +985,6 @@ bool BehaviorSettings::Save(const CComPtr& pSettingsRoot) copyPasteSettings.Save(pSettingsRoot); scrollSettings.Save(pSettingsRoot); tabHighlightSettings.Save(pSettingsRoot); -// animateSettings.Save(pSettingsRoot); return true; } @@ -1071,7 +998,6 @@ BehaviorSettings& BehaviorSettings::operator=(const BehaviorSettings& other) copyPasteSettings = other.copyPasteSettings; scrollSettings = other.scrollSettings; tabHighlightSettings= other.tabHighlightSettings; -// animateSettings = other.animateSettings; return *this; } diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index 0b519964..bb9d916d 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -329,51 +329,6 @@ struct TabHighlightSettings : public SettingsBase ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -enum AnimationDirection -{ - animDirNone = 0, - animDirPositive = 1, - animDirNegative = 2 -}; - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -enum AnimationType -{ - animTypeNone = 0, - animTypeSlide = 1, - animTypeZoom = 2, - animTypeBlend = 3 -}; - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -struct AnimateSettings : public SettingsBase -{ - AnimateSettings(); - - bool Load(const CComPtr& pSettingsRoot); - bool Save(const CComPtr& pSettingsRoot); - - AnimateSettings& operator=(const AnimateSettings& other); - - DWORD dwType; - DWORD dwHorzDirection; - DWORD dwVertDirection; - DWORD dwTime; -}; - -////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// struct BehaviorSettings : public SettingsBase @@ -388,7 +343,6 @@ struct BehaviorSettings : public SettingsBase CopyPasteSettings copyPasteSettings; ScrollSettings scrollSettings; TabHighlightSettings tabHighlightSettings; -// AnimateSettings animateSettings; }; ////////////////////////////////////////////////////////////////////////////// From 603b88bb49ebf4dcc9425d47c201bb7d6726a518 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 3 Oct 2010 09:46:54 +0200 Subject: [PATCH 050/207] restore the drop files message in elevated console --- Console/Console.cpp | 7 +++++++ Console/stdafx.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/Console/Console.cpp b/Console/Console.cpp index b05dcce9..348ffe7e 100644 --- a/Console/Console.cpp +++ b/Console/Console.cpp @@ -195,6 +195,13 @@ int Run(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWDEFAULT) return 1; } +#ifdef _USE_AERO + // restore the drop files message in elevated console + ::ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD); + ::ChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD); + ::ChangeWindowMessageFilter(0x0049, MSGFLT_ADD); +#endif + wndMain.ShowWindow(nCmdShow); int nRet = theLoop.Run(); diff --git a/Console/stdafx.h b/Console/stdafx.h index 6d32559c..673f46ec 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -71,7 +71,10 @@ extern CAppModule _Module; #include #include +#ifdef _USE_AERO #include +#include +#endif #pragma warning(disable: 4503) // disables 'name truncated' warnings From a4da14571b5eeb4e64ebbac32492f2039709d29e Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Fri, 1 Oct 2010 12:07:02 +0100 Subject: [PATCH 051/207] Added 'run as user' checkbox --- Console/Console.rc | 4 ++-- Console/MainFrame.cpp | 2 +- Console/PageSettingsTabs1.cpp | 7 ++++++- Console/PageSettingsTabs1.h | 7 +++++-- Console/SettingsHandler.cpp | 2 ++ Console/SettingsHandler.h | 2 ++ Console/resource.h | 1 + 7 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index 734e7503..efa0f653 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -420,8 +420,8 @@ BEGIN LTEXT "Startup &dir:",IDC_STATIC,7,86,38,8 EDITTEXT IDC_TAB_INIT_DIR,51,83,139,14,ES_AUTOHSCROLL PUSHBUTTON "...",IDC_BTN_BROWSE_DIR,193,83,15,14 - LTEXT "Run as user:",IDC_STATIC,7,101,42,8 - EDITTEXT IDC_TAB_USER,51,98,82,14,ES_AUTOHSCROLL + CONTROL "Run as user:",IDC_CHECK_RUN_AS_USER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,100,57,10 + EDITTEXT IDC_TAB_USER,74,98,116,14,ES_AUTOHSCROLL GROUPBOX "Shell",IDC_STATIC,0,55,217,63,WS_GROUP,WS_EX_TRANSPARENT LTEXT "Style:",IDC_STATIC,5,136,20,8 COMBOBOX IDC_COMBO_CURSOR,28,134,82,83,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index a78e890a..025129e7 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1531,7 +1531,7 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir shared_ptr consoleView(new ConsoleView(*this, dwTabIndex, strStartupDir, strStartupCmd, strDbgCmdLine, dwRows, dwColumns)); UserCredentials userCredentials; - if (tabData->strUser.length() > 0) + if (tabData->bRunAsUser) { #ifdef _USE_AERO // Display a dialog box to request credentials. diff --git a/Console/PageSettingsTabs1.cpp b/Console/PageSettingsTabs1.cpp index 0d55e994..80592931 100644 --- a/Console/PageSettingsTabs1.cpp +++ b/Console/PageSettingsTabs1.cpp @@ -21,6 +21,7 @@ PageSettingsTabs1::PageSettingsTabs1() , m_nUseDefaultIcon(0) , m_strShell(L"") , m_strInitialDir(L"") +, m_bRunAsUser(false) , m_strUser(L"") { } @@ -198,7 +199,7 @@ LRESULT PageSettingsTabs1::OnClickedBtnBrowseDir(WORD /*wNotifyCode*/, WORD /*wI ////////////////////////////////////////////////////////////////////////////// -LRESULT PageSettingsTabs1::OnCheckDefaultIcon(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +LRESULT PageSettingsTabs1::OnCheckboxClicked(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { DoDataExchange(DDX_SAVE); EnableControls(); @@ -221,6 +222,8 @@ void PageSettingsTabs1::EnableControls() GetDlgItem(IDC_TAB_ICON).EnableWindow(bEnableEditIconCtrls); GetDlgItem(IDC_BTN_BROWSE_ICON).EnableWindow(bEnableEditIconCtrls); + + GetDlgItem(IDC_TAB_USER).EnableWindow(m_bRunAsUser ? TRUE : FALSE); } ////////////////////////////////////////////////////////////////////////////// @@ -238,6 +241,7 @@ void PageSettingsTabs1::Load(shared_ptr& tabData) m_strShell = m_tabData->strShell.c_str(); m_strInitialDir = m_tabData->strInitialDir.c_str(); + m_bRunAsUser = m_tabData->bRunAsUser; m_strUser = m_tabData->strUser.c_str(); m_comboCursor.SetCurSel(m_tabData->dwCursorStyle); @@ -264,6 +268,7 @@ void PageSettingsTabs1::Save() m_tabData->strShell = m_strShell; m_tabData->strInitialDir = m_strInitialDir; + m_tabData->bRunAsUser = m_bRunAsUser; m_tabData->strUser = m_strUser; m_tabData->dwCursorStyle = m_comboCursor.GetCurSel(); diff --git a/Console/PageSettingsTabs1.h b/Console/PageSettingsTabs1.h index ebb10f54..849df0c0 100644 --- a/Console/PageSettingsTabs1.h +++ b/Console/PageSettingsTabs1.h @@ -29,6 +29,7 @@ class PageSettingsTabs1 DDX_CHECK(IDC_CHECK_DEFAULT_ICON, m_nUseDefaultIcon) DDX_TEXT(IDC_TAB_SHELL, m_strShell) DDX_TEXT(IDC_TAB_INIT_DIR, m_strInitialDir) + DDX_CHECK(IDC_CHECK_RUN_AS_USER, m_bRunAsUser) DDX_TEXT(IDC_TAB_USER, m_strUser) END_DDX_MAP() @@ -40,9 +41,10 @@ class PageSettingsTabs1 COMMAND_HANDLER(IDC_TAB_ICON, EN_CHANGE, OnTabIconChange) COMMAND_HANDLER(IDC_CURSOR_COLOR, BN_CLICKED, OnClickedCursorColor) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_ICON, OnBtnBrowseIcon) - COMMAND_ID_HANDLER(IDC_CHECK_DEFAULT_ICON, OnCheckDefaultIcon) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_SHELL, OnClickedBtnBrowseShell) COMMAND_ID_HANDLER(IDC_BTN_BROWSE_DIR, OnClickedBtnBrowseDir) + COMMAND_ID_HANDLER(IDC_CHECK_DEFAULT_ICON, OnCheckboxClicked) + COMMAND_ID_HANDLER(IDC_CHECK_RUN_AS_USER, OnCheckboxClicked) END_MSG_MAP() // Handler prototypes (uncomment arguments if needed): @@ -60,7 +62,7 @@ class PageSettingsTabs1 LRESULT OnBtnBrowseIcon(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnClickedBtnBrowseShell(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnClickedBtnBrowseDir(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); - LRESULT OnCheckDefaultIcon(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnCheckboxClicked(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); void EnableControls(); @@ -85,6 +87,7 @@ class PageSettingsTabs1 CString m_strShell; CString m_strInitialDir; + bool m_bRunAsUser; CString m_strUser; }; diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index 16427d16..97046add 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -1434,6 +1434,7 @@ bool TabSettings::Load(const CComPtr& pSettingsRoot) { XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"shell"), tabData->strShell, strDefaultShell); XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"init_dir"), tabData->strInitialDir, strDefaultInitialDir); + XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"run_as_user"), tabData->bRunAsUser, false); XmlHelper::GetAttribute(pConsoleElement, CComBSTR(L"user"), tabData->strUser, L""); } @@ -1549,6 +1550,7 @@ bool TabSettings::Save(const CComPtr& pSettingsRoot) XmlHelper::SetAttribute(pNewConsoleElement, CComBSTR(L"shell"), (*itTab)->strShell); XmlHelper::SetAttribute(pNewConsoleElement, CComBSTR(L"init_dir"), (*itTab)->strInitialDir); + XmlHelper::SetAttribute(pNewConsoleElement, CComBSTR(L"run_as_user"), (*itTab)->bRunAsUser); XmlHelper::SetAttribute(pNewConsoleElement, CComBSTR(L"user"), (*itTab)->strUser); SettingsBase::AddTextNode(pSettingsDoc, pNewTabElement, CComBSTR(L"\n\t\t\t")); diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index bb9d916d..7d8441e7 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -538,6 +538,7 @@ struct TabData , bUseDefaultIcon(false) , strShell(shell) , strInitialDir(initialDir) + , bRunAsUser(false) , strUser() , dwCursorStyle(0) , crCursorColor(RGB(255, 255, 255)) @@ -555,6 +556,7 @@ struct TabData wstring strShell; wstring strInitialDir; + bool bRunAsUser; wstring strUser; DWORD dwCursorStyle; diff --git a/Console/resource.h b/Console/resource.h index 16e365e1..6c3142f8 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -222,6 +222,7 @@ #define IDC_USER 1175 #define IDC_PASSWORD 1176 #define IDC_STATIC_TRIM_CHARS_RIGHT 1176 +#define IDC_CHECK_RUN_AS_USER 1177 #define IDC_APPTEXT 1177 #define IDC_STATIC_USER 1177 #define IDC_APPICON 1178 From 6300898147165841c8a4b0f2e28aea0ce2a04235 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 17 Oct 2010 10:17:25 -0400 Subject: [PATCH 052/207] Fix monitoring of parent process Unfortunately, there appears to be no way to monitor a process handle of another user without special permissions. The idea is: create a mutex that will be abandoned when Console terminates unexpectedly. When that happens, the child knows that it's time to exit. There is a problem: the watchdog mutex better be created in MainFrame or other single-instance class, but SharedMemNames define wformat, so it can be included only in one file (otherwise, linker complains). --- Console/ConsoleHandler.cpp | 27 ++++++++++++++++++++++++++- Console/ConsoleHandler.h | 1 + ConsoleHook/ConsoleHandler.cpp | 32 +++++++++++++++----------------- ConsoleHook/ConsoleHandler.h | 2 -- shared/SharedMemNames.h | 2 ++ 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index f782ddb6..a05c7ba8 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -23,6 +23,7 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// +static Mutex *theWatchdog; shared_ptr ConsoleHandler::s_environmentBlock; ////////////////////////////////////////////////////////////////////////////// @@ -288,6 +289,7 @@ bool ConsoleHandler::StartShellProcess // create shared memory objects CreateSharedObjects(pi.dwProcessId, strUser); + CreateWatchdog(); // write startup params m_consoleParams->dwConsoleMainThreadId = pi.dwThreadId; @@ -421,7 +423,6 @@ void ConsoleHandler::UpdateEnvironmentBlock() ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////// bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId, const wstring& strUser) @@ -466,6 +467,30 @@ bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId, const wstring return true; } +void ConsoleHandler::CreateWatchdog() +{ + if (!theWatchdog) + { + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = FALSE; + + sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, + SECURITY_DESCRIPTOR_MIN_LENGTH); + if (InitializeSecurityDescriptor(sa.lpSecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION)) + { + // Add the ACL to the security descriptor. + SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, + TRUE, // bDaclPresent flag + NULL, // NULL DACL allows full access to everyone + FALSE); + } + + theWatchdog = new Mutex(&sa, TRUE, (LPCTSTR)((SharedMemNames::formatWatchdog % ::GetCurrentProcessId()).str().c_str())); + } +} + ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index fa2e90a5..588a4288 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -87,6 +87,7 @@ class ConsoleHandler private: bool CreateSharedObjects(DWORD dwConsoleProcessId, const wstring& strUser); + void CreateWatchdog(); bool InjectHookDLL(PROCESS_INFORMATION& pi); diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index 97607891..17c0827e 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -16,8 +16,7 @@ using namespace boost; ////////////////////////////////////////////////////////////////////////////// ConsoleHandler::ConsoleHandler() -: m_hParentProcess() -, m_consoleParams() +: m_consoleParams() , m_consoleInfo() , m_cursorInfo() , m_consoleBuffer() @@ -778,13 +777,6 @@ DWORD ConsoleHandler::MonitorThread() // open shared objects (shared memory, events, etc) if (!OpenSharedObjects()) return 0; - // read parent process ID and get process handle - m_hParentProcess = shared_ptr( - ::OpenProcess(SYNCHRONIZE, FALSE, m_consoleParams->dwParentProcessId), - ::CloseHandle); - - TRACE(L"Parent process handle: 0x%08X\n", m_hParentProcess.get()); - HANDLE hStdOut = ::CreateFile( L"CONOUT$", GENERIC_WRITE | GENERIC_READ, @@ -812,6 +804,9 @@ DWORD ConsoleHandler::MonitorThread() // FIX: this seems to case problems on startup // ReadConsoleBuffer(); + HANDLE hWatchdog = ::OpenMutex(SYNCHRONIZE, FALSE, (LPCTSTR)((SharedMemNames::formatWatchdog % m_consoleParams->dwParentProcessId).str().c_str())); + TRACE(L"Watchdog handle: 0x%08X\n", hWatchdog); + HANDLE arrWaitHandles[] = { m_hMonitorThreadExit.get(), @@ -821,17 +816,23 @@ DWORD ConsoleHandler::MonitorThread() m_consoleMouseEvent.GetReqEvent(), m_newConsoleSize.GetReqEvent(), hStdOut, -// m_hParentProcess.get() }; DWORD dwWaitRes = 0; while ((dwWaitRes = ::WaitForMultipleObjects( - sizeof(arrWaitHandles)/sizeof(arrWaitHandles[0]), + sizeof(arrWaitHandles)/sizeof(arrWaitHandles[0]), arrWaitHandles, FALSE, m_consoleParams->dwRefreshInterval)) != WAIT_OBJECT_0) { + if (hWatchdog && WAIT_ABANDONED == ::WaitForSingleObject(hWatchdog, 0)) + { + TRACE(L"Watchdog 0x%08X died. Time to exit", hWatchdog); + ::SendMessage(m_consoleParams->hwndConsoleWindow, WM_CLOSE, 0, 0); + break; + } + switch (dwWaitRes) { // copy request @@ -904,15 +905,12 @@ DWORD ConsoleHandler::MonitorThread() ReadConsoleBuffer(); break; } - - // close the console if the parent process died - case WAIT_OBJECT_0 + 7: - ::SendMessage(m_consoleParams->hwndConsoleWindow, WM_CLOSE, 0, 0); - break; - } } + if (hWatchdog) + ::CloseHandle(hWatchdog); + return 0; } diff --git a/ConsoleHook/ConsoleHandler.h b/ConsoleHook/ConsoleHandler.h index fe83b991..06adec23 100644 --- a/ConsoleHook/ConsoleHandler.h +++ b/ConsoleHook/ConsoleHandler.h @@ -48,8 +48,6 @@ class ConsoleHandler private: - shared_ptr m_hParentProcess; - SharedMemory m_consoleParams; SharedMemory m_consoleInfo; SharedMemory m_cursorInfo; diff --git a/shared/SharedMemNames.h b/shared/SharedMemNames.h index 5d346eea..bb9ee1c3 100644 --- a/shared/SharedMemNames.h +++ b/shared/SharedMemNames.h @@ -15,6 +15,7 @@ class SharedMemNames static wformat formatMouseEvent; static wformat formatNewConsoleSize; static wformat formatNewScrollPos; + static wformat formatWatchdog; }; @@ -37,5 +38,6 @@ wformat SharedMemNames::formatTextInfo(L"Console2_consoleTextInfo_%1%"); wformat SharedMemNames::formatMouseEvent(L"Console2_consoleMouseEvent_%1%"); wformat SharedMemNames::formatNewConsoleSize(L"Console2_newConsoleSize_%1%"); wformat SharedMemNames::formatNewScrollPos(L"Console2_newScrollPos_%1%"); +wformat SharedMemNames::formatWatchdog(L"Local\\Console2_parentProcessExit_%1%"); ////////////////////////////////////////////////////////////////////////////// From 1befc2ac5903f2d7883b5eb5fe59d54ad1624447 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 17 Oct 2010 12:31:51 -0400 Subject: [PATCH 053/207] Use static run-time library for ConsoleWow --- ConsoleWow/ConsoleWow.vcproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ConsoleWow/ConsoleWow.vcproj b/ConsoleWow/ConsoleWow.vcproj index 02fa1d96..c0c7b01e 100644 --- a/ConsoleWow/ConsoleWow.vcproj +++ b/ConsoleWow/ConsoleWow.vcproj @@ -44,7 +44,7 @@ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" - RuntimeLibrary="3" + RuntimeLibrary="1" UsePrecompiledHeader="2" WarningLevel="3" DebugInformationFormat="4" @@ -116,7 +116,7 @@ Optimization="2" EnableIntrinsicFunctions="true" PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" - RuntimeLibrary="2" + RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="2" WarningLevel="3" From 708d0e7580c1f0a361fef77ffc09415bc9ab6e14 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Mon, 18 Oct 2010 18:45:02 +0200 Subject: [PATCH 054/207] - parent monitoring code cleanup --- Console/ConsoleHandler.cpp | 42 ++++++++++++++++++++-------------- Console/ConsoleHandler.h | 2 ++ ConsoleHook/ConsoleHandler.cpp | 11 ++++----- shared/SharedMemory.h | 2 +- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index a05c7ba8..05437c04 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -23,8 +23,8 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -static Mutex *theWatchdog; -shared_ptr ConsoleHandler::s_environmentBlock; +shared_ptr ConsoleHandler::s_parentProcessWatchdog; +shared_ptr ConsoleHandler::s_environmentBlock; ////////////////////////////////////////////////////////////////////////////// @@ -467,27 +467,35 @@ bool ConsoleHandler::CreateSharedObjects(DWORD dwConsoleProcessId, const wstring return true; } +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + void ConsoleHandler::CreateWatchdog() { - if (!theWatchdog) + if (!s_parentProcessWatchdog) { - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = FALSE; - - sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, - SECURITY_DESCRIPTOR_MIN_LENGTH); - if (InitializeSecurityDescriptor(sa.lpSecurityDescriptor, - SECURITY_DESCRIPTOR_REVISION)) + shared_ptr sd; // PSECURITY_DESCRIPTOR + + sd.reset(::LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH), ::LocalFree); + if (::InitializeSecurityDescriptor(sd.get(), SECURITY_DESCRIPTOR_REVISION)) { - // Add the ACL to the security descriptor. - SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, - TRUE, // bDaclPresent flag - NULL, // NULL DACL allows full access to everyone - FALSE); + ::SetSecurityDescriptorDacl( + sd.get(), + TRUE, // bDaclPresent flag + NULL, // full access to everyone + FALSE); // not a default DACL } - theWatchdog = new Mutex(&sa, TRUE, (LPCTSTR)((SharedMemNames::formatWatchdog % ::GetCurrentProcessId()).str().c_str())); + SECURITY_ATTRIBUTES sa; + + ::ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = FALSE; + sa.lpSecurityDescriptor = sd.get(); + + s_parentProcessWatchdog.reset(new Mutex(&sa, TRUE, (LPCTSTR)((SharedMemNames::formatWatchdog % ::GetCurrentProcessId()).str().c_str()))); } } diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index 588a4288..4d8958f8 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -124,6 +124,8 @@ class ConsoleHandler shared_ptr m_hMonitorThreadExit; static shared_ptr s_environmentBlock; + static shared_ptr s_parentProcessWatchdog; + }; ////////////////////////////////////////////////////////////////////////////// diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index 17c0827e..175d90ef 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -804,8 +804,8 @@ DWORD ConsoleHandler::MonitorThread() // FIX: this seems to case problems on startup // ReadConsoleBuffer(); - HANDLE hWatchdog = ::OpenMutex(SYNCHRONIZE, FALSE, (LPCTSTR)((SharedMemNames::formatWatchdog % m_consoleParams->dwParentProcessId).str().c_str())); - TRACE(L"Watchdog handle: 0x%08X\n", hWatchdog); + shared_ptr parentProcessWatchdog(::OpenMutex(SYNCHRONIZE, FALSE, (LPCTSTR)((SharedMemNames::formatWatchdog % m_consoleParams->dwParentProcessId).str().c_str())), ::CloseHandle); + TRACE(L"Watchdog handle: 0x%08X\n", parentProcessWatchdog.get()); HANDLE arrWaitHandles[] = { @@ -826,9 +826,9 @@ DWORD ConsoleHandler::MonitorThread() FALSE, m_consoleParams->dwRefreshInterval)) != WAIT_OBJECT_0) { - if (hWatchdog && WAIT_ABANDONED == ::WaitForSingleObject(hWatchdog, 0)) + if ((parentProcessWatchdog.get() != NULL) && (::WaitForSingleObject(parentProcessWatchdog.get(), 0) == WAIT_ABANDONED)) { - TRACE(L"Watchdog 0x%08X died. Time to exit", hWatchdog); + TRACE(L"Watchdog 0x%08X died. Time to exit", parentProcessWatchdog.get()); ::SendMessage(m_consoleParams->hwndConsoleWindow, WM_CLOSE, 0, 0); break; } @@ -908,9 +908,6 @@ DWORD ConsoleHandler::MonitorThread() } } - if (hWatchdog) - ::CloseHandle(hWatchdog); - return 0; } diff --git a/shared/SharedMemory.h b/shared/SharedMemory.h index 17f66f09..e2b59e52 100644 --- a/shared/SharedMemory.h +++ b/shared/SharedMemory.h @@ -237,7 +237,7 @@ void SharedMemory::Create(const wstring& strName, DWORD dwSize, SyncObjectTyp // initialize a security attributes structure sa.reset(new SECURITY_ATTRIBUTES); sa->nLength = sizeof (SECURITY_ATTRIBUTES); - sa->lpSecurityDescriptor = sd.get(); + sa->lpSecurityDescriptor= sd.get(); sa->bInheritHandle = FALSE; } From 6d740356095943c621a7790d4923c3b23084ac18 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Mon, 1 Nov 2010 12:01:26 +0100 Subject: [PATCH 055/207] Version info for new build --- Console/Console.rc | 8 +-- ConsoleHook/ConsoleHook.rc | 8 +-- ConsoleWow/ConsoleWow.rc | 104 +++++++++++++++++++++++++++++++++++ ConsoleWow/ConsoleWow.vcproj | 8 +++ ConsoleWow/resource.h | 14 +++++ 5 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 ConsoleWow/ConsoleWow.rc create mode 100644 ConsoleWow/resource.h diff --git a/Console/Console.rc b/Console/Console.rc index efa0f653..8a10751d 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -712,8 +712,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,146 - PRODUCTVERSION 2,0,0,146 + FILEVERSION 2,0,0,147 + PRODUCTVERSION 2,0,0,147 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -731,13 +731,13 @@ BEGIN VALUE "Comments", "Tabbed cool console window (THIS IS NOT A SHELL :-)" VALUE "CompanyName", "Ingenuity Unlimited Ltd." VALUE "FileDescription", "Main Console module" - VALUE "FileVersion", "2.00, Build 146 2010.04.19" + VALUE "FileVersion", "2.00, Build 147 2010.11.01" VALUE "InternalName", "Console" VALUE "LegalCopyright", "Copyright © 2001-2010 Marko Bozikovic" VALUE "LegalTrademarks", "Copyright © 2001-2010 Marko Bozikovic" VALUE "OriginalFilename", "Console.exe" VALUE "ProductName", "Console" - VALUE "ProductVersion", "2, 0, 0, 146" + VALUE "ProductVersion", "2, 0, 0, 147" END END BLOCK "VarFileInfo" diff --git a/ConsoleHook/ConsoleHook.rc b/ConsoleHook/ConsoleHook.rc index 8780db11..e2f4895b 100644 --- a/ConsoleHook/ConsoleHook.rc +++ b/ConsoleHook/ConsoleHook.rc @@ -53,8 +53,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,146 - PRODUCTVERSION 2,0,0,146 + FILEVERSION 2,0,0,147 + PRODUCTVERSION 2,0,0,147 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -72,13 +72,13 @@ BEGIN VALUE "Comments", "Tabbed cool console window (THIS IS NOT A SHELL :-)" VALUE "CompanyName", "Ingenuity Unlimited Ltd." VALUE "FileDescription", "Console process hook module" - VALUE "FileVersion", "2.00, Build 146 2010.04.19" + VALUE "FileVersion", "2.00, Build 147 2010.11.01" VALUE "InternalName", "Console" VALUE "LegalCopyright", "Copyright © 2001-2010 Marko Bozikovic" VALUE "LegalTrademarks", "Copyright © 2001-2010 Marko Bozikovic" VALUE "OriginalFilename", "Console.exe" VALUE "ProductName", "Console" - VALUE "ProductVersion", "2.00.00.146" + VALUE "ProductVersion", "2, 0, 0, 147" END END BLOCK "VarFileInfo" diff --git a/ConsoleWow/ConsoleWow.rc b/ConsoleWow/ConsoleWow.rc new file mode 100644 index 00000000..7f1c769f --- /dev/null +++ b/ConsoleWow/ConsoleWow.rc @@ -0,0 +1,104 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Croatian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_HRV) +#ifdef _WIN32 +LANGUAGE LANG_CROATIAN, SUBLANG_DEFAULT +#pragma code_page(1250) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,0,147 + PRODUCTVERSION 2,0,0,147 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "Tabbed cool console window (THIS IS NOT A SHELL :-)" + VALUE "CompanyName", "Ingenuity Unlimited Ltd." + VALUE "FileDescription", "Console WOW64 helper process" + VALUE "FileVersion", "2.00, Build 147 2010.11.01" + VALUE "InternalName", "Console" + VALUE "LegalCopyright", "Copyright © 2001-2010 Marko Bozikovic" + VALUE "LegalTrademarks", "Copyright © 2001-2010 Marko Bozikovic" + VALUE "OriginalFilename", "ConsoleWow.exe" + VALUE "ProductName", "Console" + VALUE "ProductVersion", "2, 0, 0, 147" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // Croatian resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/ConsoleWow/ConsoleWow.vcproj b/ConsoleWow/ConsoleWow.vcproj index c0c7b01e..b8c322bf 100644 --- a/ConsoleWow/ConsoleWow.vcproj +++ b/ConsoleWow/ConsoleWow.vcproj @@ -202,6 +202,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + @@ -216,6 +220,10 @@ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > + + Date: Mon, 1 Nov 2010 13:34:50 +0100 Subject: [PATCH 056/207] Fixed build number in the about dialog --- Console/stdafx.h | 2 +- ConsoleHook/stdafx.h | 2 +- ConsoleWow/stdafx.h | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Console/stdafx.h b/Console/stdafx.h index 673f46ec..3542e75f 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -128,7 +128,7 @@ using namespace boost::multi_index; #define VERSION_MAJOR 2 #define VERSION_MINOR 0 -#define VERSION_BUILD 146 +#define VERSION_BUILD 147 ////////////////////////////////////////////////////////////////////////////// diff --git a/ConsoleHook/stdafx.h b/ConsoleHook/stdafx.h index 19239036..1647b40f 100644 --- a/ConsoleHook/stdafx.h +++ b/ConsoleHook/stdafx.h @@ -50,7 +50,7 @@ using namespace boost; #define VERSION_MAJOR 2 #define VERSION_MINOR 0 -#define VERSION_BUILD 146 +#define VERSION_BUILD 147 ////////////////////////////////////////////////////////////////////////////// diff --git a/ConsoleWow/stdafx.h b/ConsoleWow/stdafx.h index b700aa29..5dfe7f45 100644 --- a/ConsoleWow/stdafx.h +++ b/ConsoleWow/stdafx.h @@ -10,3 +10,14 @@ #include #include + + +////////////////////////////////////////////////////////////////////////////// +// Version numbers + +#define VERSION_MAJOR 2 +#define VERSION_MINOR 0 +#define VERSION_BUILD 147 + +////////////////////////////////////////////////////////////////////////////// + From 9351c07e388750d681e4f223ddf300e357241366 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Mon, 1 Nov 2010 13:00:43 +0100 Subject: [PATCH 057/207] Fixed visual styles support --- Console/stdafx.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Console/stdafx.h b/Console/stdafx.h index 3542e75f..d3b175b8 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -59,6 +59,16 @@ extern CAppModule _Module; #pragma comment (lib, "gdiplus.lib") #endif +#if defined _M_IX86 + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_IA64 + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_X64 + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#else + #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#endif + #include "CustomTabCtrl.h" #include "DotNetTabCtrl.h" #ifdef _USE_AERO From 077006e061d65fc6df3fa5c7337db0e243e18a4d Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 7 Feb 2010 04:36:09 +0100 Subject: [PATCH 058/207] Add support for zooming with standard ctrl+wheel Now font size can be temporarily changed with usual Windows gesture - Ctrl+Mouse Wheel. This fix is discussed on Sourceforge in [ 1733641 ] Hotkey to resize fonts. The calculation of GetMaxRect is modified to allow zooming beyond main-screen limit, imposed by the design of cmd.exe. When the limit was enforced, Console did not calculate the new buffer size correctly. --- Console/ConsoleView.cpp | 20 ++++++++++++++++++++ Console/MainFrame.h | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 49e35593..8dd59993 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -311,6 +311,24 @@ LRESULT ConsoleView::OnConsoleFwdMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BO { if (((uMsg == WM_KEYDOWN) || (uMsg == WM_KEYUP)) && (wParam == VK_PACKET)) return 0; + if (uMsg == WM_MOUSEWHEEL && wParam & MK_CONTROL) { + short direction = HIWORD(wParam); + + // calculate new font size in the [5, 36] interval + DWORD size = max(5, min(36, m_appearanceSettings.fontSettings.dwSize + direction / 120)); + + // only if the new size is different (to avoid flickering at extremes) + if (m_appearanceSettings.fontSettings.dwSize != size) { + // adjust the font size + m_appearanceSettings.fontSettings.dwSize = size; + RecreateOffscreenBuffers(); + m_mainFrame.AdjustWindowSize(false); + Repaint(true); + } + + return 0; + } + if (!TranslateKeyDown(uMsg, wParam, lParam)) { // TRACE(L"Msg: 0x%04X, wParam: 0x%08X, lParam: 0x%08X\n", uMsg, wParam, lParam); @@ -962,6 +980,7 @@ bool ConsoleView::GetMaxRect(CRect& maxClientRect) maxClientRect.right = m_consoleHandler.GetConsoleParams()->dwMaxColumns*m_nCharWidth + 2*stylesSettings.dwInsideBorder; maxClientRect.bottom= m_consoleHandler.GetConsoleParams()->dwMaxRows*m_nCharHeight + 2*stylesSettings.dwInsideBorder; + /* TODO: this calculation does not work very well for multiple monitors CWindow desktopWindow(::GetDesktopWindow()); CRect rectDesktop; bool bRecalc = false; @@ -985,6 +1004,7 @@ bool ConsoleView::GetMaxRect(CRect& maxClientRect) maxClientRect.right = m_consoleHandler.GetConsoleParams()->dwMaxColumns*m_nCharWidth + 2*stylesSettings.dwInsideBorder; maxClientRect.bottom= m_consoleHandler.GetConsoleParams()->dwMaxRows*m_nCharHeight + 2*stylesSettings.dwInsideBorder; } + */ if (m_bShowVScroll) maxClientRect.right += m_nVScrollWidth; if (m_bShowHScroll) maxClientRect.bottom+= m_nHScrollWidth; diff --git a/Console/MainFrame.h b/Console/MainFrame.h index d44f8b44..cef364de 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -195,6 +195,7 @@ class MainFrame void AdjustWindowRect(CRect& rect); void SetSelectionSize(int iSelectionSize); + void AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore = false); private: @@ -218,7 +219,6 @@ class MainFrame void ShowStatusbar(BOOL bShow); void ResizeWindow(); - void AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore = false); void SetMargins(); void SetTransparency(); void CreateAcceleratorTable(); From 7ed2cc8bfce328438d3c636f08ba887327232a52 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 7 Feb 2010 01:34:54 -0500 Subject: [PATCH 059/207] Attempt to improve visual feedback during resizing The drag rectangle will jump to a possible position as determined by the used font. --- Console/ConsoleView.h | 1 + Console/MainFrame.cpp | 32 ++++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index 5f26f1f8..11da5a11 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -102,6 +102,7 @@ class ConsoleView void GetRect(CRect& clientRect); bool GetMaxRect(CRect& maxClientRect); void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge, bool bGetClientRect); + CPoint GetCellSize() { return CPoint(m_nCharWidth, m_nCharHeight); }; ConsoleHandler& GetConsoleHandler() { return m_consoleHandler; } shared_ptr GetTabData() { return m_tabData; } diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 025129e7..d6a9045f 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -570,17 +570,33 @@ LRESULT MainFrame::OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& ////////////////////////////////////////////////////////////////////////////// -LRESULT MainFrame::OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) +LRESULT MainFrame::OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { - // Start timer that will force a call to ResizeWindow (called from WM_EXITSIZEMOVE handler - // when the Console window is resized using a mouse) - // External utilities that might resize Console window usually don't send WM_EXITSIZEMOVE - // message after resizing a window. - SetTimer(TIMER_SIZING, TIMER_SIZING_INTERVAL); + m_dwResizeWindowEdge = static_cast(wParam); - if (m_activeView.get() != NULL) m_activeView->SetResizing(true); + if (!m_activeView) + return 0; + + m_activeView->SetResizing(true); + + CPoint pointSize = m_activeView->GetCellSize(); + RECT *rectNew = (RECT *)lParam; + + CRect rectWindow; + GetWindowRect(&rectWindow); + + if (rectWindow.top != rectNew->top) + rectNew->top += (rectWindow.top - rectNew->top) - (rectWindow.top - rectNew->top) / pointSize.y * pointSize.y; + + if (rectWindow.bottom != rectNew->bottom) + rectNew->bottom += (rectWindow.bottom - rectNew->bottom) - (rectWindow.bottom - rectNew->bottom) / pointSize.y * pointSize.y; + + if (rectWindow.left != rectNew->left) + rectNew->left += (rectWindow.left - rectNew->left) - (rectWindow.left - rectNew->left) / pointSize.x * pointSize.x; + + if (rectWindow.right != rectNew->right) + rectNew->right += (rectWindow.right - rectNew->right) - (rectWindow.right - rectNew->right) / pointSize.x * pointSize.x; - m_dwResizeWindowEdge = static_cast(wParam); return 0; } From f15cf0bd398817c201050c32d29fa0a090f20a30 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 12 Feb 2011 08:22:19 +0100 Subject: [PATCH 060/207] add quake like console style with activation hotkey --- Console/Console.rc | 5 +-- Console/DlgSettingsStyles.cpp | 2 ++ Console/DlgSettingsStyles.h | 2 ++ Console/MainFrame.cpp | 65 ++++++++++++++++++++++++----------- Console/SettingsHandler.cpp | 4 +++ Console/SettingsHandler.h | 1 + Console/resource.h | 1 + 7 files changed, 57 insertions(+), 23 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index 8a10751d..b3340adc 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -313,6 +313,7 @@ BEGIN CONTROL "Bo&rder *",IDC_CHECK_STYLE_BORDER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,36,43,10 CONTROL "Tas&kbar button *",IDC_CHECK_STYLE_TASKBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,12,68,10 CONTROL "Tra&y icon",IDC_CHECK_STYLE_TRAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,24,45,10 + CONTROL "Quake like",IDC_CHECK_STYLE_QUAKE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,36,49,10 LTEXT "Inside &border:",IDC_STATIC,102,53,46,8 EDITTEXT IDC_INSIDE_BORDER,153,50,33,14,ES_AUTOHSCROLL CONTROL "",IDC_SPIN_INSIDE_BORDER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,191,50,11,14 @@ -370,7 +371,7 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_LIST_TABS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,0,128,75 PUSHBUTTON "Add",IDC_BTN_ADD,129,0,50,14 - PUSHBUTTON "Clone",IDC_BTN_CLONE,129,14,50,14 + PUSHBUTTON "Clone",IDC_BTN_CLONE,129,14,50,14 PUSHBUTTON "Delete",IDC_BTN_DELETE,129,28,50,14 PUSHBUTTON "Move up",IDC_BTN_UP,130,46,50,14 PUSHBUTTON "Move down",IDC_BTN_DOWN,130,61,50,14 @@ -975,7 +976,7 @@ END // // Generated from the TEXTINCLUDE 3 resource. // - + ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/Console/DlgSettingsStyles.cpp b/Console/DlgSettingsStyles.cpp index c7e28c54..654e7ca3 100644 --- a/Console/DlgSettingsStyles.cpp +++ b/Console/DlgSettingsStyles.cpp @@ -49,6 +49,7 @@ LRESULT DlgSettingsStyles::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM m_nTaskbarButton= m_stylesSettings.bTaskbarButton ? 1 : 0; m_nBorder = m_stylesSettings.bBorder ? 1 : 0; m_nTrayIcon = m_stylesSettings.bTrayIcon ? 1 : 0; + m_nQuake = m_stylesSettings.bQuake ? 1 : 0; CUpDownCtrl spin; @@ -151,6 +152,7 @@ LRESULT DlgSettingsStyles::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWn m_stylesSettings.bTaskbarButton = (m_nTaskbarButton > 0); m_stylesSettings.bBorder = (m_nBorder > 0); m_stylesSettings.bTrayIcon = (m_nTrayIcon > 0); + m_stylesSettings.bQuake = (m_nQuake > 0); m_transparencySettings.byActiveAlpha = static_cast(255 - m_sliderActiveAlpha.GetPos()); m_transparencySettings.byInactiveAlpha = static_cast(255 - m_sliderInactiveAlpha.GetPos()); diff --git a/Console/DlgSettingsStyles.h b/Console/DlgSettingsStyles.h index 5144a592..2fe6ba1a 100644 --- a/Console/DlgSettingsStyles.h +++ b/Console/DlgSettingsStyles.h @@ -34,6 +34,7 @@ class DlgSettingsStyles DDX_CHECK(IDC_CHECK_STYLE_BORDER, m_nBorder) DDX_CHECK(IDC_CHECK_STYLE_TASKBAR, m_nTaskbarButton) DDX_CHECK(IDC_CHECK_STYLE_TRAY, m_nTrayIcon) + DDX_CHECK(IDC_CHECK_STYLE_QUAKE, m_nQuake) DDX_UINT(IDC_INSIDE_BORDER, m_stylesSettings.dwInsideBorder) DDX_RADIO(IDC_TRANSPARENCY_TYPE, reinterpret_cast(m_transparencySettings.transType)) END_DDX_MAP() @@ -97,6 +98,7 @@ class DlgSettingsStyles int m_nTaskbarButton; int m_nBorder; int m_nTrayIcon; + int m_nQuake; int m_nTransparencyType; }; diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index d6a9045f..26675c65 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -412,30 +412,53 @@ LRESULT MainFrame::OnActivateApp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/ LRESULT MainFrame::OnHotKey(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { - switch (wParam) - { - case IDC_GLOBAL_ACTIVATE : - { - ShowWindow(SW_RESTORE); - PostMessage(WM_ACTIVATEAPP, TRUE, 0); + switch (wParam) + { + case IDC_GLOBAL_ACTIVATE : + { + bool bQuake = g_settingsHandler->GetAppearanceSettings().stylesSettings.bQuake; + bool bActivate = true; - POINT cursorPos; - CRect windowRect; + if( bQuake ) + { + if(!::IsWindowVisible(m_hWnd)) + { + ::AnimateWindow(m_hWnd, 350, AW_ACTIVATE | AW_SLIDE | AW_VER_POSITIVE); + } + else + { + ::AnimateWindow(m_hWnd, 350, AW_HIDE | AW_SLIDE | AW_VER_NEGATIVE); + bActivate = false; + } + } + else + { + ShowWindow(SW_RESTORE); + } - ::GetCursorPos(&cursorPos); - GetWindowRect(&windowRect); + if( bActivate ) + { + PostMessage(WM_ACTIVATEAPP, TRUE, 0); - if ((cursorPos.x < windowRect.left) || (cursorPos.x > windowRect.right)) cursorPos.x = windowRect.left + windowRect.Width()/2; - if ((cursorPos.y < windowRect.top) || (cursorPos.y > windowRect.bottom)) cursorPos.y = windowRect.top + windowRect.Height()/2; + POINT cursorPos; + CRect windowRect; - ::SetCursorPos(cursorPos.x, cursorPos.y); - ::SetForegroundWindow(m_hWnd); - break; - } + ::GetCursorPos(&cursorPos); + GetWindowRect(&windowRect); - } + if ((cursorPos.x < windowRect.left) || (cursorPos.x > windowRect.right)) cursorPos.x = windowRect.left + windowRect.Width()/2; + if ((cursorPos.y < windowRect.top) || (cursorPos.y > windowRect.bottom)) cursorPos.y = windowRect.top + windowRect.Height()/2; - return 0; + ::SetCursorPos(cursorPos.x, cursorPos.y); + ::SetForegroundWindow(m_hWnd); + } + + break; + } + + } + + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -2133,10 +2156,10 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal // if we're being maximized, AdjustRectAndResize will use client rect supplied m_activeView->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge, !bMaxOrRestore); - + // for other views, first set view size and then resize their Windows consoles MutexLock viewMapLock(m_viewsMutex); - + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) { if (it->second->m_hWnd == m_activeView->m_hWnd) continue; @@ -2148,7 +2171,7 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal clientRect.Width(), clientRect.Height(), SWP_NOMOVE|SWP_NOZORDER|SWP_NOSENDCHANGING); - + // if we're being maximized, AdjustRectAndResize will use client rect supplied it->second->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge, !bMaxOrRestore); } diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index 97046add..ba5eb88f 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -458,6 +458,7 @@ StylesSettings::StylesSettings() , bBorder(true) , dwInsideBorder(2) , bTrayIcon(false) +, bQuake(false) , crSelectionColor(RGB(255, 255, 255)) { } @@ -479,6 +480,7 @@ bool StylesSettings::Load(const CComPtr& pSettingsRoot) XmlHelper::GetAttribute(pStylesElement, CComBSTR(L"border"), bBorder, true); XmlHelper::GetAttribute(pStylesElement, CComBSTR(L"inside_border"), dwInsideBorder, 2); XmlHelper::GetAttribute(pStylesElement, CComBSTR(L"tray_icon"), bTrayIcon, false); + XmlHelper::GetAttribute(pStylesElement, CComBSTR(L"quake_like"), bQuake, false); CComPtr pSelColorElement; @@ -506,6 +508,7 @@ bool StylesSettings::Save(const CComPtr& pSettingsRoot) XmlHelper::SetAttribute(pStylesElement, CComBSTR(L"border"), bBorder); XmlHelper::SetAttribute(pStylesElement, CComBSTR(L"inside_border"), dwInsideBorder); XmlHelper::SetAttribute(pStylesElement, CComBSTR(L"tray_icon"), bTrayIcon); + XmlHelper::SetAttribute(pStylesElement, CComBSTR(L"quake_like"), bQuake); CComPtr pSelColorElement; @@ -529,6 +532,7 @@ StylesSettings& StylesSettings::operator=(const StylesSettings& other) bBorder = other.bBorder; dwInsideBorder = other.dwInsideBorder; bTrayIcon = other.bTrayIcon; + bQuake = other.bQuake; crSelectionColor= other.crSelectionColor; return *this; diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index 7d8441e7..e3422799 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -162,6 +162,7 @@ struct StylesSettings : public SettingsBase bool bBorder; DWORD dwInsideBorder; bool bTrayIcon; + bool bQuake; COLORREF crSelectionColor; }; diff --git a/Console/resource.h b/Console/resource.h index 6c3142f8..28c82ab3 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -126,6 +126,7 @@ #define IDC_RADIO_DOCK_NONE 1095 #define IDC_CHECK_FLAT_SCROLLBARS 1095 #define IDC_RADIO_DOCK_TL 1096 +#define IDC_CHECK_STYLE_QUAKE 1096 #define IDC_RADIO_DOCK_TR 1097 #define IDC_RADIO_DOCK_BL 1098 #define IDC_RADIO_DOCK_BR 1099 From 0dfba48f288ea408df3803cc0e96d1742b44db27 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 12 Feb 2011 10:40:13 +0100 Subject: [PATCH 061/207] add support for maximized console with dynamic inside borders --- Console/ConsoleView.cpp | 151 ++++++++++++++++------------------- Console/ConsoleView.h | 3 + Console/MainFrame.cpp | 5 +- Console/SelectionHandler.cpp | 31 +++---- Console/SelectionHandler.h | 6 +- 5 files changed, 100 insertions(+), 96 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 8dd59993..d98f0b1d 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -46,6 +46,8 @@ ConsoleView::ConsoleView(MainFrame& mainFrame, DWORD dwTabIndex, const wstring& , m_bShowHScroll(false) , m_nVScrollWidth(::GetSystemMetrics(SM_CXVSCROLL)) , m_nHScrollWidth(::GetSystemMetrics(SM_CXHSCROLL)) +, m_nVInsideBorder(g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder) +, m_nHInsideBorder(g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder) , m_strTitle(g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]->strTitle.c_str()) , m_strUser() , bigIcon() @@ -201,7 +203,6 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B // TODO: put this in console size change handler m_screenBuffer.reset(new CharInfo[m_consoleHandler.GetConsoleParams()->dwRows*m_consoleHandler.GetConsoleParams()->dwColumns]); -// ::ZeroMemory(m_screenBuffer.get(), sizeof(CHAR_INFO)*m_consoleHandler.GetConsoleParams()->dwRows*m_consoleHandler.GetConsoleParams()->dwColumns); m_consoleHandler.StartMonitorThread(); @@ -589,22 +590,20 @@ LRESULT ConsoleView::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& CRect rectClient; GetClientRect(&rectClient); - DWORD dwInsideBorder = g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder; - - if (point.x < rectClient.left + static_cast(dwInsideBorder)) + if (point.x < rectClient.left + m_nVInsideBorder) { DoScroll(SB_HORZ, SB_LINELEFT, 0); - } - else if (point.x > rectClient.right - static_cast(dwInsideBorder)) + } + else if (point.x > rectClient.right - m_nVInsideBorder) { DoScroll(SB_HORZ, SB_LINERIGHT, 0); } - if (point.y < rectClient.top + static_cast(dwInsideBorder)) + if (point.y < rectClient.top + m_nHInsideBorder) { DoScroll(SB_VERT, SB_LINEUP, 0); } - else if (point.y > rectClient.bottom - static_cast(dwInsideBorder)) + else if (point.y > rectClient.bottom - m_nHInsideBorder) { DoScroll(SB_VERT, SB_LINEDOWN, 0); } @@ -952,12 +951,10 @@ LRESULT ConsoleView::OnScrollCommand(WORD /*wNotifyCode*/, WORD wID, HWND /*hWnd void ConsoleView::GetRect(CRect& clientRect) { - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; - clientRect.left = 0; clientRect.top = 0; - clientRect.right = m_consoleHandler.GetConsoleParams()->dwColumns*m_nCharWidth + 2*stylesSettings.dwInsideBorder; - clientRect.bottom = m_consoleHandler.GetConsoleParams()->dwRows*m_nCharHeight + 2*stylesSettings.dwInsideBorder; + clientRect.right = m_consoleHandler.GetConsoleParams()->dwColumns * m_nCharWidth + 2 * m_nVInsideBorder; + clientRect.bottom = m_consoleHandler.GetConsoleParams()->dwRows * m_nCharHeight + 2 * m_nHInsideBorder; if (m_bShowVScroll) clientRect.right += m_nVScrollWidth; if (m_bShowHScroll) clientRect.bottom += m_nHScrollWidth; @@ -980,32 +977,6 @@ bool ConsoleView::GetMaxRect(CRect& maxClientRect) maxClientRect.right = m_consoleHandler.GetConsoleParams()->dwMaxColumns*m_nCharWidth + 2*stylesSettings.dwInsideBorder; maxClientRect.bottom= m_consoleHandler.GetConsoleParams()->dwMaxRows*m_nCharHeight + 2*stylesSettings.dwInsideBorder; - /* TODO: this calculation does not work very well for multiple monitors - CWindow desktopWindow(::GetDesktopWindow()); - CRect rectDesktop; - bool bRecalc = false; - - desktopWindow.GetWindowRect(rectDesktop); - - if (rectDesktop.Width() < maxClientRect.Width()) - { - m_consoleHandler.GetConsoleParams()->dwMaxColumns = (rectDesktop.Width() - 2*stylesSettings.dwInsideBorder) / m_nCharWidth; - bRecalc = true; - } - - if (rectDesktop.Height() < maxClientRect.Height()) - { - m_consoleHandler.GetConsoleParams()->dwMaxRows = (rectDesktop.Height() - 2*stylesSettings.dwInsideBorder) / m_nCharHeight; - bRecalc = true; - } - - if (bRecalc) - { - maxClientRect.right = m_consoleHandler.GetConsoleParams()->dwMaxColumns*m_nCharWidth + 2*stylesSettings.dwInsideBorder; - maxClientRect.bottom= m_consoleHandler.GetConsoleParams()->dwMaxRows*m_nCharHeight + 2*stylesSettings.dwInsideBorder; - } - */ - if (m_bShowVScroll) maxClientRect.right += m_nVScrollWidth; if (m_bShowHScroll) maxClientRect.bottom+= m_nHScrollWidth; @@ -1026,21 +997,46 @@ void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdg TRACE(L"================================================================\n"); TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); */ + LONG width = clientRect.right - clientRect.left; + LONG height = clientRect.bottom - clientRect.top; // exclude scrollbars from row/col calculation - if (m_bShowVScroll) clientRect.right -= m_nVScrollWidth; - if (m_bShowHScroll) clientRect.bottom -= m_nHScrollWidth; - - // TODO: handle variable fonts - DWORD dwColumns = (clientRect.Width() - 2*stylesSettings.dwInsideBorder) / m_nCharWidth; - DWORD dwRows = (clientRect.Height() - 2*stylesSettings.dwInsideBorder) / m_nCharHeight; - - clientRect.right = clientRect.left + dwColumns*m_nCharWidth + 2*stylesSettings.dwInsideBorder; - clientRect.bottom = clientRect.top + dwRows*m_nCharHeight + 2*stylesSettings.dwInsideBorder; - - // adjust for scrollbars - if (m_bShowVScroll) clientRect.right += m_nVScrollWidth; - if (m_bShowHScroll) clientRect.bottom += m_nHScrollWidth; + if (m_bShowVScroll) width -= m_nVScrollWidth; + if (m_bShowHScroll) height -= m_nHScrollWidth; + + // exclude inside borders from row/col calculation + if (!bGetClientRect) + { + m_nVInsideBorder = stylesSettings.dwInsideBorder; + m_nHInsideBorder = stylesSettings.dwInsideBorder; + width -= (m_nVInsideBorder * 2); + height -= (m_nHInsideBorder * 2); + } + + DWORD dwColumns = width / m_nCharWidth; + DWORD dwRows = height / m_nCharHeight; + + DWORD dwMaxColumns = this->m_consoleHandler.GetConsoleParams()->dwMaxColumns; + DWORD dwMaxRows = this->m_consoleHandler.GetConsoleParams()->dwMaxRows; + + if( dwColumns > dwMaxColumns ) + dwColumns = dwMaxColumns; + if( dwRows > dwMaxRows ) + dwRows = dwMaxRows; + + // variable inside borders + if (bGetClientRect) + { + m_nVInsideBorder = (width - dwColumns * m_nCharWidth ) / 2; + m_nHInsideBorder = (height - dwRows * m_nCharHeight) / 2; + } + + clientRect.right = clientRect.left + dwColumns * m_nCharWidth + m_nVInsideBorder * 2; + clientRect.bottom = clientRect.top + dwRows * m_nCharHeight + m_nHInsideBorder * 2; + + // adjust for scrollbars + if (m_bShowVScroll) clientRect.right += m_nVScrollWidth; + if (m_bShowHScroll) clientRect.bottom += m_nHScrollWidth; SharedMemory& newConsoleSize = m_consoleHandler.GetNewConsoleSize(); SharedMemoryLock memLock(newConsoleSize); @@ -1323,7 +1319,7 @@ void ConsoleView::OnConsoleChange(bool bResize) // console size changed, resize local buffer if (bResize) - { + { m_screenBuffer.reset(new CharInfo[dwBufferSize]); } @@ -1406,7 +1402,7 @@ void ConsoleView::CreateOffscreenBuffers() } // get max window rect based on font and console size - GetMaxRect(rectWindowMax); + //GetMaxRect(rectWindowMax); GetRect(rectWindowMax); // create offscreen bitmaps if needed @@ -1432,8 +1428,10 @@ void ConsoleView::CreateOffscreenBuffers() m_consoleHandler.GetConsoleParams(), m_consoleHandler.GetConsoleInfo(), m_consoleHandler.GetCopyInfo(), - m_nCharWidth, - m_nCharHeight)); + m_nCharWidth, + m_nCharHeight, + m_nVInsideBorder, + m_nHInsideBorder)); // create and initialize cursor CRect rectCursor(0, 0, m_nCharWidth, m_nCharHeight); @@ -1749,12 +1747,11 @@ void ConsoleView::RepaintText(CDC& dc) } } - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; SharedMemory& consoleParams = m_consoleHandler.GetConsoleParams(); MutexLock bufferLock(m_bufferMutex); - DWORD dwX = stylesSettings.dwInsideBorder; - DWORD dwY = stylesSettings.dwInsideBorder; + DWORD dwX = m_nVInsideBorder; + DWORD dwY = m_nHInsideBorder; DWORD dwOffset = 0; WORD attrBG; @@ -1771,8 +1768,8 @@ void ConsoleView::RepaintText(CDC& dc) for (DWORD i = 0; i < consoleParams->dwRows; ++i) { - dwX = stylesSettings.dwInsideBorder; - dwY = i*m_nCharHeight + stylesSettings.dwInsideBorder; + dwX = m_nVInsideBorder; + dwY = i*m_nCharHeight + m_nHInsideBorder; nBkMode = TRANSPARENT; crBkColor = RGB(0, 0, 0); @@ -1884,10 +1881,8 @@ void ConsoleView::RepaintText(CDC& dc) void ConsoleView::RepaintTextChanges(CDC& dc) { - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; - - DWORD dwX = stylesSettings.dwInsideBorder; - DWORD dwY = stylesSettings.dwInsideBorder; + DWORD dwX = m_nVInsideBorder; + DWORD dwY = m_nHInsideBorder; DWORD dwOffset = 0; WORD attrBG; @@ -1901,8 +1896,8 @@ void ConsoleView::RepaintTextChanges(CDC& dc) for (DWORD i = 0; i < m_consoleHandler.GetConsoleParams()->dwRows; ++i) { - dwX = stylesSettings.dwInsideBorder; - dwY = i*m_nCharHeight + stylesSettings.dwInsideBorder; + dwX = m_nVInsideBorder; + dwY = i*m_nCharHeight + m_nHInsideBorder; for (DWORD j = 0; j < m_consoleHandler.GetConsoleParams()->dwColumns; ++j, ++dwOffset, dwX += m_nCharWidth) { @@ -1984,7 +1979,6 @@ void ConsoleView::RepaintTextChanges(CDC& dc) void ConsoleView::BitBltOffscreen(bool bOnlyCursor /*= false*/) { CRect rectBlit; - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; if (bOnlyCursor) { @@ -1994,10 +1988,10 @@ void ConsoleView::BitBltOffscreen(bool bOnlyCursor /*= false*/) SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); rectBlit = m_cursor->GetCursorRect(); - rectBlit.left += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; - rectBlit.top += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; - rectBlit.right += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; - rectBlit.bottom += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; + rectBlit.left += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + m_nVInsideBorder; + rectBlit.top += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + m_nHInsideBorder; + rectBlit.right += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + m_nVInsideBorder; + rectBlit.bottom += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + m_nHInsideBorder; } else { @@ -2038,7 +2032,6 @@ void ConsoleView::UpdateOffscreen(const CRect& rectBlit) { CRect rectCursor(0, 0, 0, 0); SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; // don't blit if cursor is outside visible window if ((consoleInfo->csbi.dwCursorPosition.X >= consoleInfo->csbi.srWindow.Left) && @@ -2047,10 +2040,10 @@ void ConsoleView::UpdateOffscreen(const CRect& rectBlit) (consoleInfo->csbi.dwCursorPosition.Y <= consoleInfo->csbi.srWindow.Bottom)) { rectCursor = m_cursor->GetCursorRect(); - rectCursor.left += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; - rectCursor.top += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; - rectCursor.right += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + stylesSettings.dwInsideBorder; - rectCursor.bottom += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + stylesSettings.dwInsideBorder; + rectCursor.left += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + m_nVInsideBorder; + rectCursor.top += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + m_nHInsideBorder; + rectCursor.right += (consoleInfo->csbi.dwCursorPosition.X - consoleInfo->csbi.srWindow.Left) * m_nCharWidth + m_nVInsideBorder; + rectCursor.bottom += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + m_nHInsideBorder; m_cursor->BitBlt( m_dcOffscreen, @@ -2296,8 +2289,6 @@ void ConsoleView::ForwardMouseClick(UINT uMsg, WPARAM wParam, const CPoint& poin COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint) { - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; - DWORD dwColumns = m_consoleHandler.GetConsoleParams()->dwColumns; DWORD dwBufferColumns = m_consoleHandler.GetConsoleParams()->dwBufferColumns; SMALL_RECT& srWindow = m_consoleHandler.GetConsoleInfo()->csbi.srWindow; @@ -2306,8 +2297,8 @@ COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint) COORD consolePoint; SHORT maxX = (dwBufferColumns > 0) ? static_cast(dwBufferColumns - 1) : static_cast(dwColumns - 1); - consolePoint.X = static_cast((point.x - static_cast(stylesSettings.dwInsideBorder)) / m_nCharWidth + srWindow.Left); - consolePoint.Y = static_cast((point.y - static_cast(stylesSettings.dwInsideBorder)) / m_nCharHeight + srWindow.Top); + consolePoint.X = static_cast((point.x - m_nVInsideBorder) / m_nCharWidth + srWindow.Left); + consolePoint.Y = static_cast((point.y - m_nHInsideBorder) / m_nCharHeight + srWindow.Top); if (consolePoint.X < 0) { diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index 11da5a11..6a372248 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -190,6 +190,9 @@ class ConsoleView bool m_bShowHScroll; int m_nVScrollWidth; int m_nHScrollWidth; + int m_nVInsideBorder; + int m_nHInsideBorder; + CString m_strTitle; CString m_strUser; diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 26675c65..9fdb6b4f 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1845,7 +1845,7 @@ void MainFrame::SetWindowStyles() DWORD dwStyle = GetWindowLong(GWL_STYLE); DWORD dwExStyle = GetWindowLong(GWL_EXSTYLE); - dwStyle &= ~WS_MAXIMIZEBOX; + //dwStyle &= ~WS_MAXIMIZEBOX; if (!stylesSettings.bCaption) dwStyle &= ~WS_CAPTION; if (!stylesSettings.bResizable) dwStyle &= ~WS_THICKFRAME; @@ -2130,6 +2130,9 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal { CRect clientRect(0, 0, 0, 0); + if( this->IsZoomed() ) + bResizeConsole = true; + if (bResizeConsole) { if (bMaxOrRestore) diff --git a/Console/SelectionHandler.cpp b/Console/SelectionHandler.cpp index a5365186..6708ac5f 100644 --- a/Console/SelectionHandler.cpp +++ b/Console/SelectionHandler.cpp @@ -22,7 +22,9 @@ SelectionHandler::SelectionHandler( SharedMemory& consoleInfo, SharedMemory& consoleCopyInfo, int nCharWidth, - int nCharHeight) + int nCharHeight, + int nVInsideBorder, + int nHInsideBorder) : m_consoleView(consoleView) , m_dcSelection(::CreateCompatibleDC(NULL)) //, m_bmpSelection(::CreateCompatibleBitmap(dcConsoleView, rectConsoleView.Width(), rectConsoleView.Height())) @@ -34,6 +36,8 @@ SelectionHandler::SelectionHandler( , m_consoleInfo(consoleInfo) , m_consoleCopyInfo(consoleCopyInfo) , m_nCharHeight(nCharHeight) +, m_nVInsideBorder(nVInsideBorder) +, m_nHInsideBorder(nHInsideBorder) , m_paintBrush() , m_backgroundBrush(::CreateSolidBrush(RGB(0, 0, 0))) , m_selectionState(selstateNoSelection) @@ -377,29 +381,28 @@ void SelectionHandler::GetSelectionCoordinates(COORD& coordStart, COORD& coordEn void SelectionHandler::GetFillRect(const COORD& coordStart, const COORD& coordEnd, CRect& fillRect) { - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; SMALL_RECT& srWindow = m_consoleInfo->csbi.srWindow; CRect rectConsoleView; m_consoleView.GetClientRect(&rectConsoleView); - fillRect.left = (coordStart.X - srWindow.Left) * m_nCharWidth + static_cast(stylesSettings.dwInsideBorder); - fillRect.top = (coordStart.Y - srWindow.Top) * m_nCharHeight + static_cast(stylesSettings.dwInsideBorder); + fillRect.left = (coordStart.X - srWindow.Left) * m_nCharWidth + m_nVInsideBorder; + fillRect.top = (coordStart.Y - srWindow.Top) * m_nCharHeight + m_nHInsideBorder; - fillRect.right = (coordEnd.X - srWindow.Left + 1) * m_nCharWidth + static_cast(stylesSettings.dwInsideBorder); - fillRect.bottom = (coordEnd.Y - srWindow.Top + 1) * m_nCharHeight + static_cast(stylesSettings.dwInsideBorder); + fillRect.right = (coordEnd.X - srWindow.Left + 1) * m_nCharWidth + m_nVInsideBorder; + fillRect.bottom = (coordEnd.Y - srWindow.Top + 1) * m_nCharHeight + m_nHInsideBorder; - if (fillRect.left < static_cast(stylesSettings.dwInsideBorder)) fillRect.left = stylesSettings.dwInsideBorder; - if (fillRect.top < static_cast(stylesSettings.dwInsideBorder)) fillRect.top = stylesSettings.dwInsideBorder; + if (fillRect.left < m_nVInsideBorder) fillRect.left = m_nVInsideBorder; + if (fillRect.top < m_nHInsideBorder) fillRect.top = m_nHInsideBorder; - if (fillRect.left > (rectConsoleView.right - static_cast(stylesSettings.dwInsideBorder))) fillRect.right = rectConsoleView.right - static_cast(stylesSettings.dwInsideBorder); - if (fillRect.top > (rectConsoleView.bottom - static_cast(stylesSettings.dwInsideBorder))) fillRect.bottom = rectConsoleView.bottom - static_cast(stylesSettings.dwInsideBorder); + if (fillRect.left > (rectConsoleView.right - m_nVInsideBorder)) fillRect.right = rectConsoleView.right - m_nVInsideBorder; + if (fillRect.top > (rectConsoleView.bottom - m_nHInsideBorder)) fillRect.bottom = rectConsoleView.bottom - m_nHInsideBorder; - if (fillRect.right < static_cast(stylesSettings.dwInsideBorder)) fillRect.right = stylesSettings.dwInsideBorder; - if (fillRect.bottom < static_cast(stylesSettings.dwInsideBorder)) fillRect.bottom = stylesSettings.dwInsideBorder; + if (fillRect.right < m_nVInsideBorder) fillRect.right = m_nVInsideBorder; + if (fillRect.bottom < m_nHInsideBorder) fillRect.bottom = m_nHInsideBorder; - if (fillRect.right > (rectConsoleView.right - static_cast(stylesSettings.dwInsideBorder))) fillRect.right = rectConsoleView.right - static_cast(stylesSettings.dwInsideBorder); - if (fillRect.bottom > (rectConsoleView.bottom - static_cast(stylesSettings.dwInsideBorder))) fillRect.bottom = rectConsoleView.bottom - static_cast(stylesSettings.dwInsideBorder); + if (fillRect.right > (rectConsoleView.right - m_nVInsideBorder)) fillRect.right = rectConsoleView.right - m_nVInsideBorder; + if (fillRect.bottom > (rectConsoleView.bottom - m_nHInsideBorder)) fillRect.bottom = rectConsoleView.bottom - m_nHInsideBorder; } ///////////////////////////////////////////////////////////////////////////// diff --git a/Console/SelectionHandler.h b/Console/SelectionHandler.h index bda6d791..d43f4fe5 100644 --- a/Console/SelectionHandler.h +++ b/Console/SelectionHandler.h @@ -32,7 +32,9 @@ class SelectionHandler SharedMemory& consoleInfo, SharedMemory& consoleCopyInfo, int nCharWidth, - int nCharHeight); + int nCharHeight, + int nVInsideBorder, + int nHInsideBorder); ~SelectionHandler(); @@ -70,6 +72,8 @@ class SelectionHandler SharedMemory& m_consoleCopyInfo; int m_nCharWidth; int m_nCharHeight; + int m_nVInsideBorder; + int m_nHInsideBorder; CBrush m_paintBrush; CBrush m_backgroundBrush; From 745ebd00542142d62b966019a757d1bf8bc23e04 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 12 Feb 2011 10:51:27 +0100 Subject: [PATCH 062/207] fix a crash size of screen buffer (=number of rows * number of columns) can be modified by console handler when the buffer is used for console painting --- Console/Console.vcproj | 4 +++- Console/ConsoleHandler.cpp | 3 +++ Console/ConsoleHandler.h | 2 ++ Console/ConsoleView.cpp | 6 ++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Console/Console.vcproj b/Console/Console.vcproj index 95aa9901..9bc6e375 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -422,7 +422,7 @@ UsePrecompiledHeader="2" WarningLevel="4" Detect64BitPortabilityProblems="false" - DebugInformationFormat="0" + DebugInformationFormat="3" /> (::CreateEvent(NULL, FALSE, FALSE, NULL), ::CloseHandle)) +, m_resizingMutex(NULL, FALSE, NULL) { } @@ -775,6 +776,8 @@ DWORD ConsoleHandler::MonitorThread() ((m_consoleParams->dwBufferColumns != 0) && (m_consoleParams->dwBufferColumns != dwBufferColumns)) || ((m_consoleParams->dwBufferRows != 0) && (m_consoleParams->dwBufferRows != dwBufferRows))) { + MutexLock handlerLock(m_resizingMutex); + m_consoleParams->dwColumns = dwColumns; m_consoleParams->dwRows = dwRows; diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index 4d8958f8..ecc63b86 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -47,6 +47,8 @@ class ConsoleHandler ConsoleHandler(); ~ConsoleHandler(); + Mutex m_resizingMutex; + public: void SetupDelegates(ConsoleChangeDelegate consoleChangeDelegate, ConsoleCloseDelegate consoleCloseDelegate); diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index d98f0b1d..68337782 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -1307,6 +1307,8 @@ void ConsoleView::DumpBuffer() void ConsoleView::OnConsoleChange(bool bResize) { + MutexLock handlerLock(m_consoleHandler.m_resizingMutex); + SharedMemory& consoleParams = m_consoleHandler.GetConsoleParams(); DWORD dwBufferSize = consoleParams->dwRows * consoleParams->dwColumns; @@ -1698,6 +1700,8 @@ void ConsoleView::UpdateTitle() void ConsoleView::RepaintText(CDC& dc) { + MutexLock handlerLock(m_consoleHandler.m_resizingMutex); + SIZE bitmapSize; CRect bitmapRect; @@ -1881,6 +1885,8 @@ void ConsoleView::RepaintText(CDC& dc) void ConsoleView::RepaintTextChanges(CDC& dc) { + MutexLock handlerLock(m_consoleHandler.m_resizingMutex); + DWORD dwX = m_nVInsideBorder; DWORD dwY = m_nHInsideBorder; DWORD dwOffset = 0; From 86de3522289941d86c31e8c0a2a6740503ee22e4 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 13 Feb 2011 09:55:25 +0100 Subject: [PATCH 063/207] fix : maximized console size is computed by system --- Console/MainFrame.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Console/MainFrame.h b/Console/MainFrame.h index cef364de..1344c2ae 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -72,7 +72,7 @@ class MainFrame MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeydown) MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) - MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) +// MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_SIZING, OnSizing) MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChanging) From 9ec488f64c8cac24d3c8eb9fa44a4efa54c17880 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 13 Feb 2011 09:57:29 +0100 Subject: [PATCH 064/207] no maximize button for no resizable console --- Console/MainFrame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 9fdb6b4f..77d5e244 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1845,7 +1845,7 @@ void MainFrame::SetWindowStyles() DWORD dwStyle = GetWindowLong(GWL_STYLE); DWORD dwExStyle = GetWindowLong(GWL_EXSTYLE); - //dwStyle &= ~WS_MAXIMIZEBOX; + if (!stylesSettings.bResizable) dwStyle &= ~WS_MAXIMIZEBOX; if (!stylesSettings.bCaption) dwStyle &= ~WS_CAPTION; if (!stylesSettings.bResizable) dwStyle &= ~WS_THICKFRAME; From cc7d36d5bc0927c985ccde81ea2bed40020feb95 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 13 Feb 2011 21:58:46 +0100 Subject: [PATCH 065/207] fix a crash size of screen buffer (=number of rows * number of columns) can be modified by console handler when the buffer is used for console painting --- Console/ConsoleHandler.cpp | 4 +-- Console/ConsoleHandler.h | 2 +- Console/ConsoleView.cpp | 55 ++++++++++++++++++-------------------- Console/ConsoleView.h | 4 +-- 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index 330297f0..ad342a0a 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -40,7 +40,7 @@ ConsoleHandler::ConsoleHandler() , m_newScrollPos() , m_hMonitorThread() , m_hMonitorThreadExit(shared_ptr(::CreateEvent(NULL, FALSE, FALSE, NULL), ::CloseHandle)) -, m_resizingMutex(NULL, FALSE, NULL) +, m_bufferMutex(NULL, FALSE, NULL) { } @@ -776,7 +776,7 @@ DWORD ConsoleHandler::MonitorThread() ((m_consoleParams->dwBufferColumns != 0) && (m_consoleParams->dwBufferColumns != dwBufferColumns)) || ((m_consoleParams->dwBufferRows != 0) && (m_consoleParams->dwBufferRows != dwBufferRows))) { - MutexLock handlerLock(m_resizingMutex); + MutexLock handlerLock(m_bufferMutex); m_consoleParams->dwColumns = dwColumns; m_consoleParams->dwRows = dwRows; diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index ecc63b86..fdff9809 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -47,7 +47,7 @@ class ConsoleHandler ConsoleHandler(); ~ConsoleHandler(); - Mutex m_resizingMutex; + Mutex m_bufferMutex; public: diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 68337782..27e9644b 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -54,6 +54,8 @@ ConsoleView::ConsoleView(MainFrame& mainFrame, DWORD dwTabIndex, const wstring& , smallIcon() , m_consoleHandler() , m_screenBuffer() +, m_dwScreenRows(0) +, m_dwScreenColumns(0) , m_consoleSettings(g_settingsHandler->GetConsoleSettings()) , m_appearanceSettings(g_settingsHandler->GetAppearanceSettings()) , m_hotkeys(g_settingsHandler->GetHotKeys()) @@ -63,7 +65,6 @@ ConsoleView::ConsoleView(MainFrame& mainFrame, DWORD dwTabIndex, const wstring& , m_cursor() , m_selectionHandler() , m_mouseCommand(MouseSettings::cmdNone) -, m_bufferMutex(NULL, FALSE, NULL) , m_bFlashTimerRunning(false) , m_dwFlashes(0) { @@ -202,7 +203,9 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B CreateOffscreenBuffers(); // TODO: put this in console size change handler - m_screenBuffer.reset(new CharInfo[m_consoleHandler.GetConsoleParams()->dwRows*m_consoleHandler.GetConsoleParams()->dwColumns]); + m_dwScreenRows = m_consoleHandler.GetConsoleParams()->dwRows; + m_dwScreenColumns = m_consoleHandler.GetConsoleParams()->dwColumns; + m_screenBuffer.reset(new CharInfo[m_dwScreenRows * m_dwScreenColumns]); m_consoleHandler.StartMonitorThread(); @@ -472,7 +475,7 @@ LRESULT ConsoleView::OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL { ::SetCursor(::LoadCursor(NULL, IDC_IBEAM)); - MutexLock bufferLock(m_bufferMutex); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); m_selectionHandler->StartSelection(GetConsoleCoord(point), m_appearanceSettings.stylesSettings.crSelectionColor, m_screenBuffer); m_mouseCommand = MouseSettings::cmdSelect; @@ -609,12 +612,12 @@ LRESULT ConsoleView::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& } { - MutexLock bufferLock(m_bufferMutex); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); m_selectionHandler->UpdateSelection(GetConsoleCoord(point), m_screenBuffer); COORD coordStart; COORD coordEnd; m_selectionHandler->GetSelectionCoordinates(coordStart, coordEnd); - int iSelectionSize = (coordEnd.Y - coordStart.Y) * m_consoleHandler.GetConsoleParams()->dwColumns + + int iSelectionSize = (coordEnd.Y - coordStart.Y) * m_dwScreenColumns + (coordEnd.X - coordStart.X) + 1; m_mainFrame.SetSelectionSize(iSelectionSize); } @@ -850,7 +853,7 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* ::GetCursorPos(&point); ScreenToClient(&point); - MutexLock bufferLock(m_bufferMutex); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); m_selectionHandler->UpdateSelection(GetConsoleCoord(point), m_screenBuffer); } else if (m_selectionHandler->GetState() == SelectionHandler::selstateSelected) @@ -1279,11 +1282,11 @@ void ConsoleView::DumpBuffer() wofstream of; of.open(Helpers::ExpandEnvironmentStrings(_T("%temp%\\console.dump")).c_str()); DWORD dwOffset = 0; - MutexLock bufferLock(m_bufferMutex); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); - for (DWORD i = 0; i < m_consoleHandler.GetConsoleParams()->dwRows; ++i) + for (DWORD i = 0; i < m_dwScreenRows; ++i) { - for (DWORD j = 0; j < m_consoleHandler.GetConsoleParams()->dwColumns; ++j) + for (DWORD j = 0; j < m_dwScreenColumns; ++j) { of << m_screenBuffer[dwOffset].charInfo.Char.UnicodeChar; ++dwOffset; @@ -1307,23 +1310,22 @@ void ConsoleView::DumpBuffer() void ConsoleView::OnConsoleChange(bool bResize) { - MutexLock handlerLock(m_consoleHandler.m_resizingMutex); - SharedMemory& consoleParams = m_consoleHandler.GetConsoleParams(); - DWORD dwBufferSize = consoleParams->dwRows * consoleParams->dwColumns; - SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); SharedMemory& consoleBuffer = m_consoleHandler.GetConsoleBuffer(); SharedMemoryLock consoleInfoLock(consoleInfo); SharedMemoryLock sharedBufferLock(consoleBuffer); - MutexLock localBufferLock(m_bufferMutex); + MutexLock localBufferLock(m_consoleHandler.m_bufferMutex); // console size changed, resize local buffer if (bResize) - { - m_screenBuffer.reset(new CharInfo[dwBufferSize]); + { + m_dwScreenRows = consoleParams->dwRows; + m_dwScreenColumns = consoleParams->dwColumns; + m_screenBuffer.reset(new CharInfo[m_dwScreenRows * m_dwScreenColumns]); } + DWORD dwBufferSize = m_dwScreenRows * m_dwScreenColumns; // copy changed data for (DWORD dwOffset = 0; dwOffset < dwBufferSize; ++dwOffset) @@ -1658,9 +1660,9 @@ void ConsoleView::DoScroll(int nType, int nScrollCode, int nThumbPos) DWORD ConsoleView::GetBufferDifference() { - DWORD dwCount = m_consoleHandler.GetConsoleParams()->dwRows * m_consoleHandler.GetConsoleParams()->dwColumns; + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); + DWORD dwCount = m_dwScreenRows * m_dwScreenColumns; DWORD dwChangedPositions = 0; - MutexLock bufferLock(m_bufferMutex); for (DWORD i = 0; i < dwCount; ++i) { @@ -1700,8 +1702,6 @@ void ConsoleView::UpdateTitle() void ConsoleView::RepaintText(CDC& dc) { - MutexLock handlerLock(m_consoleHandler.m_resizingMutex); - SIZE bitmapSize; CRect bitmapRect; @@ -1751,8 +1751,7 @@ void ConsoleView::RepaintText(CDC& dc) } } - SharedMemory& consoleParams = m_consoleHandler.GetConsoleParams(); - MutexLock bufferLock(m_bufferMutex); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); DWORD dwX = m_nVInsideBorder; DWORD dwY = m_nHInsideBorder; @@ -1770,7 +1769,7 @@ void ConsoleView::RepaintText(CDC& dc) wstring strText(L""); - for (DWORD i = 0; i < consoleParams->dwRows; ++i) + for (DWORD i = 0; i < m_dwScreenRows; ++i) { dwX = m_nVInsideBorder; dwY = i*m_nCharHeight + m_nHInsideBorder; @@ -1807,7 +1806,7 @@ void ConsoleView::RepaintText(CDC& dc) nCharWidths = 1; ++dwOffset; - for (DWORD j = 1; j < consoleParams->dwColumns; ++j, ++dwOffset) + for (DWORD j = 1; j < m_dwScreenColumns; ++j, ++dwOffset) { if (m_screenBuffer[dwOffset].charInfo.Attributes & COMMON_LVB_TRAILING_BYTE) { @@ -1885,27 +1884,25 @@ void ConsoleView::RepaintText(CDC& dc) void ConsoleView::RepaintTextChanges(CDC& dc) { - MutexLock handlerLock(m_consoleHandler.m_resizingMutex); - DWORD dwX = m_nVInsideBorder; DWORD dwY = m_nHInsideBorder; DWORD dwOffset = 0; WORD attrBG; - MutexLock bufferLock(m_bufferMutex); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); CRect rectWindow; GetClientRect(&rectWindow); if (m_tabData->backgroundImageType != bktypeNone) g_imageHandler->UpdateImageBitmap(dc, rectWindow, m_background); - for (DWORD i = 0; i < m_consoleHandler.GetConsoleParams()->dwRows; ++i) + for (DWORD i = 0; i < m_dwScreenRows; ++i) { dwX = m_nVInsideBorder; dwY = i*m_nCharHeight + m_nHInsideBorder; - for (DWORD j = 0; j < m_consoleHandler.GetConsoleParams()->dwColumns; ++j, ++dwOffset, dwX += m_nCharWidth) + for (DWORD j = 0; j < m_dwScreenColumns; ++j, ++dwOffset, dwX += m_nCharWidth) { if (m_screenBuffer[dwOffset].changed) { diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index 6a372248..50cba293 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -204,6 +204,8 @@ class ConsoleView ConsoleHandler m_consoleHandler; shared_array m_screenBuffer; + DWORD m_dwScreenRows; + DWORD m_dwScreenColumns; ConsoleSettings& m_consoleSettings; AppearanceSettings& m_appearanceSettings; @@ -219,8 +221,6 @@ class ConsoleView MouseSettings::Command m_mouseCommand; - Mutex m_bufferMutex; - bool m_bFlashTimerRunning; DWORD m_dwFlashes; From ad128fd80b83b7d32d859c925c47a18c5d5f197a Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 20 Feb 2011 21:43:59 +0100 Subject: [PATCH 066/207] selection handler was created before resizing with maximized console selection handler and offscreen buffers must be recreated for all consoles ! --- Console/ConsoleView.cpp | 27 +++++++++++++++++---------- Console/ConsoleView.h | 1 + Console/MainFrame.cpp | 14 +++++++++++++- Console/MainFrame.h | 1 + 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 27e9644b..79e604b8 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -199,6 +199,9 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B // scrollbar stuff InitializeScrollbars(); + // create font + RecreateFont(); + // create offscreen buffers CreateOffscreenBuffers(); @@ -325,8 +328,10 @@ LRESULT ConsoleView::OnConsoleFwdMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BO if (m_appearanceSettings.fontSettings.dwSize != size) { // adjust the font size m_appearanceSettings.fontSettings.dwSize = size; - RecreateOffscreenBuffers(); + // recreate font with new size + RecreateFont(); m_mainFrame.AdjustWindowSize(false); + m_mainFrame.RecreateOffscreenBuffers(); Repaint(true); } @@ -794,7 +799,7 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* */ InitializeScrollbars(); - if (m_bActive) RecreateOffscreenBuffers(); + RecreateOffscreenBuffers(); // notify parent about resize m_mainFrame.SendMessage(UM_CONSOLE_RESIZED, 0, 0); @@ -1092,13 +1097,22 @@ void ConsoleView::SetAppActiveStatus(bool bAppActive) ////////////////////////////////////////////////////////////////////////////// -void ConsoleView::RecreateOffscreenBuffers() +void ConsoleView::RecreateFont() { if (!m_fontText.IsNull()) m_fontText.DeleteObject(); + if (!CreateFont(m_appearanceSettings.fontSettings.strName)) + { + CreateFont(wstring(L"Courier New")); + } +} + +void ConsoleView::RecreateOffscreenBuffers() +{ if (!m_backgroundBrush.IsNull())m_backgroundBrush.DeleteObject(); if (!m_bmpOffscreen.IsNull()) m_bmpOffscreen.DeleteObject(); if (!m_bmpText.IsNull()) m_bmpText.DeleteObject(); CreateOffscreenBuffers(); + m_bNeedFullRepaint = true; } ////////////////////////////////////////////////////////////////////////////// @@ -1369,13 +1383,6 @@ void ConsoleView::CreateOffscreenBuffers() { CWindowDC dcWindow(m_hWnd); CRect rectWindowMax; -// CRect rectWindow; - - // create font - if (!CreateFont(m_appearanceSettings.fontSettings.strName)) - { - CreateFont(wstring(L"Courier New")); - } // get ClearType status BOOL bSmoothing = FALSE; diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index 50cba293..b0cb85f1 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -112,6 +112,7 @@ class ConsoleView void SetAppActiveStatus(bool bAppActive); + void RecreateFont(); void RecreateOffscreenBuffers(); void Repaint(bool bFullRepaint); void MainframeMoving(); diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 77d5e244..0fec0b1e 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1402,8 +1402,10 @@ LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn SetZOrder(g_settingsHandler->GetAppearanceSettings().positionSettings.zOrder); m_activeView->InitializeScrollbars(); - m_activeView->RecreateOffscreenBuffers(); + + m_activeView->RecreateFont(); AdjustWindowSize(false); + RecreateOffscreenBuffers(); m_activeView->Repaint(true); } @@ -2213,6 +2215,16 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal SetMargins(); } +void MainFrame::RecreateOffscreenBuffers() +{ + MutexLock viewMapLock(m_viewsMutex); + + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->RecreateOffscreenBuffers(); + } +} + ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 1344c2ae..42370266 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -196,6 +196,7 @@ class MainFrame void AdjustWindowRect(CRect& rect); void SetSelectionSize(int iSelectionSize); void AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore = false); + void RecreateOffscreenBuffers(); private: From f35e5b0d301074f4a3b0591a3b21cb3480fca1d0 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 20 Feb 2011 21:54:03 +0100 Subject: [PATCH 067/207] code cleanup variable inside border only with maximized console --- Console/ConsoleView.cpp | 42 +++++-------------- Console/ConsoleView.h | 8 ++-- Console/MainFrame.cpp | 90 +++++------------------------------------ Console/MainFrame.h | 3 +- 4 files changed, 25 insertions(+), 118 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 79e604b8..4e353603 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -25,6 +25,9 @@ CFont ConsoleView::m_fontText; int ConsoleView::m_nCharHeight(0); int ConsoleView::m_nCharWidth(0); +int ConsoleView::m_nVInsideBorder(0); +int ConsoleView::m_nHInsideBorder(0); + ////////////////////////////////////////////////////////////////////////////// @@ -46,8 +49,6 @@ ConsoleView::ConsoleView(MainFrame& mainFrame, DWORD dwTabIndex, const wstring& , m_bShowHScroll(false) , m_nVScrollWidth(::GetSystemMetrics(SM_CXVSCROLL)) , m_nHScrollWidth(::GetSystemMetrics(SM_CXHSCROLL)) -, m_nVInsideBorder(g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder) -, m_nHInsideBorder(g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder) , m_strTitle(g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]->strTitle.c_str()) , m_strUser() , bigIcon() @@ -973,34 +974,11 @@ void ConsoleView::GetRect(CRect& clientRect) ////////////////////////////////////////////////////////////////////////////// -bool ConsoleView::GetMaxRect(CRect& maxClientRect) +void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge, bool bVariableInsideBorder) { - if (m_bInitializing) return false; - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; - // TODO: take care of max window size - maxClientRect.left = 0; - maxClientRect.top = 0; - maxClientRect.right = m_consoleHandler.GetConsoleParams()->dwMaxColumns*m_nCharWidth + 2*stylesSettings.dwInsideBorder; - maxClientRect.bottom= m_consoleHandler.GetConsoleParams()->dwMaxRows*m_nCharHeight + 2*stylesSettings.dwInsideBorder; - - if (m_bShowVScroll) maxClientRect.right += m_nVScrollWidth; - if (m_bShowHScroll) maxClientRect.bottom+= m_nHScrollWidth; - - return true; -} - -////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////// - -void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge, bool bGetClientRect) -{ - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; - - if (bGetClientRect) GetWindowRect(&clientRect); + GetWindowRect(&clientRect); /* TRACE(L"================================================================\n"); TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); @@ -1013,7 +991,7 @@ void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdg if (m_bShowHScroll) height -= m_nHScrollWidth; // exclude inside borders from row/col calculation - if (!bGetClientRect) + if (!bVariableInsideBorder) { m_nVInsideBorder = stylesSettings.dwInsideBorder; m_nHInsideBorder = stylesSettings.dwInsideBorder; @@ -1033,7 +1011,7 @@ void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdg dwRows = dwMaxRows; // variable inside borders - if (bGetClientRect) + if (bVariableInsideBorder) { m_nVInsideBorder = (width - dwColumns * m_nCharWidth ) / 2; m_nHInsideBorder = (height - dwRows * m_nCharHeight) / 2; @@ -1412,8 +1390,7 @@ void ConsoleView::CreateOffscreenBuffers() m_bUseTextAlphaBlend = false; } - // get max window rect based on font and console size - //GetMaxRect(rectWindowMax); + // get window rect based on font and console size GetRect(rectWindowMax); // create offscreen bitmaps if needed @@ -1519,6 +1496,9 @@ bool ConsoleView::CreateFont(const wstring& strFontName) m_nCharWidth = textMetric.tmAveCharWidth; m_nCharHeight = textMetric.tmHeight; + m_nVInsideBorder = g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder; + m_nHInsideBorder = g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder; + return true; } diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index b0cb85f1..268e5a8e 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -100,8 +100,7 @@ class ConsoleView public: void GetRect(CRect& clientRect); - bool GetMaxRect(CRect& maxClientRect); - void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge, bool bGetClientRect); + void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge, bool bVariableInsideBorder); CPoint GetCellSize() { return CPoint(m_nCharWidth, m_nCharHeight); }; ConsoleHandler& GetConsoleHandler() { return m_consoleHandler; } @@ -191,9 +190,6 @@ class ConsoleView bool m_bShowHScroll; int m_nVScrollWidth; int m_nHScrollWidth; - int m_nVInsideBorder; - int m_nHInsideBorder; - CString m_strTitle; CString m_strUser; @@ -243,6 +239,8 @@ class ConsoleView static int m_nCharHeight; static int m_nCharWidth; + static int m_nVInsideBorder; + static int m_nHInsideBorder; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 0fec0b1e..3ee206d2 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -507,39 +507,6 @@ LRESULT MainFrame::OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, ////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////// - -LRESULT MainFrame::OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) -{ - MINMAXINFO* pMinMax = (MINMAXINFO*)lParam; - - CRect maxClientRect; - - if (!(m_activeView) || (!m_activeView->GetMaxRect(maxClientRect))) - { - bHandled = false; - return 1; - } - - TRACE(L"minmax: %ix%i\n", maxClientRect.Width(), maxClientRect.Height()); - - AdjustWindowRect(maxClientRect); - - TRACE(L"minmax: %ix%i\n", maxClientRect.Width(), maxClientRect.Height()); - - pMinMax->ptMaxSize.x = maxClientRect.Width(); - pMinMax->ptMaxSize.y = maxClientRect.Height() + 4; - - pMinMax->ptMaxTrackSize.x = pMinMax->ptMaxSize.x; - pMinMax->ptMaxTrackSize.y = pMinMax->ptMaxSize.y; - - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// LRESULT MainFrame::OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) @@ -548,7 +515,7 @@ LRESULT MainFrame::OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& // when the Console window is resized using a mouse) // External utilities that might resize Console window usually don't send WM_EXITSIZEMOVE // message after resizing a window. - SetTimer(TIMER_SIZING, TIMER_SIZING_INTERVAL); + //SetTimer(TIMER_SIZING, TIMER_SIZING_INTERVAL); if (wParam == SIZE_MAXIMIZED) { @@ -558,24 +525,6 @@ LRESULT MainFrame::OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& { m_bRestoringWindow = false; PostMessage(WM_EXITSIZEMOVE, 1, 0); -/* - CRect rectWindow; - GetWindowRect(&rectWindow); - - DWORD dwWindowWidth = LOWORD(lParam); - DWORD dwWindowHeight= HIWORD(lParam); - - if ((dwWindowWidth != m_dwWindowWidth) || - (dwWindowHeight != m_dwWindowHeight)) - { -// AdjustWindowSize(true, (wParam == SIZE_MAXIMIZED)); - - CRect clientRect; - GetClientRect(&clientRect); - AdjustAndResizeConsoleView(clientRect); - AdjustWindowRect(clientRect); - } -*/ } // CRect rectWindow; @@ -2114,7 +2063,7 @@ void MainFrame::ResizeWindow() if ((dwWindowWidth != m_dwWindowWidth) || (dwWindowHeight != m_dwWindowHeight)) { - AdjustWindowSize(true, false); + AdjustWindowSize(true); } SendMessage(WM_NULL, 0, 0); @@ -2128,39 +2077,24 @@ void MainFrame::ResizeWindow() ////////////////////////////////////////////////////////////////////////////// -void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= false*/) +void MainFrame::AdjustWindowSize(bool bResizeConsole) { CRect clientRect(0, 0, 0, 0); + bool bMaximized = false; if( this->IsZoomed() ) + { + bMaximized = true; bResizeConsole = true; + } if (bResizeConsole) { - if (bMaxOrRestore) - { - GetClientRect(&clientRect); - - // adjust for the toolbar height - CReBarCtrl rebar(m_hWndToolBar); - clientRect.bottom -= rebar.GetBarHeight(); - - if (m_bStatusBarVisible) - { - CRect rectStatusBar(0, 0, 0, 0); - - ::GetWindowRect(m_hWndStatusBar, &rectStatusBar); - clientRect.bottom -= rectStatusBar.Height(); - } - - clientRect.top += GetTabAreaHeight(); //+0 - } - // adjust the active view if (!m_activeView) return; // if we're being maximized, AdjustRectAndResize will use client rect supplied - m_activeView->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge, !bMaxOrRestore); + m_activeView->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge, bMaximized); // for other views, first set view size and then resize their Windows consoles MutexLock viewMapLock(m_viewsMutex); @@ -2178,18 +2112,14 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore /*= fal SWP_NOMOVE|SWP_NOZORDER|SWP_NOSENDCHANGING); // if we're being maximized, AdjustRectAndResize will use client rect supplied - it->second->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge, !bMaxOrRestore); + it->second->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge, bMaximized); } } else { if (!m_activeView) return; - CRect maxClientRect; - m_activeView->GetMaxRect(maxClientRect); - m_activeView->GetRect(clientRect); - if (clientRect.Width() > maxClientRect.Width()) clientRect.right = maxClientRect.right; - if (clientRect.Height() > maxClientRect.Height()) clientRect.bottom = maxClientRect.bottom; + m_activeView->GetRect(clientRect); } AdjustWindowRect(clientRect); diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 42370266..71cb2384 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -139,7 +139,6 @@ class MainFrame LRESULT OnSysKeydown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled); - LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled); LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled); @@ -195,7 +194,7 @@ class MainFrame void AdjustWindowRect(CRect& rect); void SetSelectionSize(int iSelectionSize); - void AdjustWindowSize(bool bResizeConsole, bool bMaxOrRestore = false); + void AdjustWindowSize(bool bResizeConsole); void RecreateOffscreenBuffers(); private: From 0d71a238b294be490a29c70987bfd20509e33fbe Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 20 Feb 2011 22:29:20 +0100 Subject: [PATCH 068/207] start position of selection could be the last char of previous line ... --- Console/ConsoleView.cpp | 15 +++++++++++---- Console/ConsoleView.h | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 4e353603..06dd6bf2 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -482,7 +482,7 @@ LRESULT ConsoleView::OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL ::SetCursor(::LoadCursor(NULL, IDC_IBEAM)); MutexLock bufferLock(m_consoleHandler.m_bufferMutex); - m_selectionHandler->StartSelection(GetConsoleCoord(point), m_appearanceSettings.stylesSettings.crSelectionColor, m_screenBuffer); + m_selectionHandler->StartSelection(GetConsoleCoord(point, true), m_appearanceSettings.stylesSettings.crSelectionColor, m_screenBuffer); m_mouseCommand = MouseSettings::cmdSelect; return 0; @@ -2277,7 +2277,7 @@ void ConsoleView::ForwardMouseClick(UINT uMsg, WPARAM wParam, const CPoint& poin ///////////////////////////////////////////////////////////////////////////// -COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint) +COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint, bool bStartSelection) { DWORD dwColumns = m_consoleHandler.GetConsoleParams()->dwColumns; DWORD dwBufferColumns = m_consoleHandler.GetConsoleParams()->dwBufferColumns; @@ -2292,8 +2292,15 @@ COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint) if (consolePoint.X < 0) { - consolePoint.X = maxX; - --consolePoint.Y; + if (bStartSelection) + { + consolePoint.X = 0; + } + else + { + consolePoint.X = maxX; + --consolePoint.Y; + } } if (consolePoint.X > srWindow.Right) consolePoint.X = srWindow.Right; diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index 268e5a8e..ddad483b 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -164,7 +164,7 @@ class ConsoleView bool TranslateKeyDown(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/); void ForwardMouseClick(UINT uMsg, WPARAM wParam, const CPoint& point); - COORD GetConsoleCoord(const CPoint& clientPoint); + COORD GetConsoleCoord(const CPoint& clientPoint, bool bStartSelection = false); private: From abfdba8ddfeb9e99c759f78e0e4c54c86c49787f Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 20 Feb 2011 22:34:36 +0100 Subject: [PATCH 069/207] bug fix : modification of scrollbar settings affects all consoles --- Console/MainFrame.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 3ee206d2..1aeab1cd 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1350,7 +1350,10 @@ LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn SetZOrder(g_settingsHandler->GetAppearanceSettings().positionSettings.zOrder); - m_activeView->InitializeScrollbars(); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->InitializeScrollbars(); + } m_activeView->RecreateFont(); AdjustWindowSize(false); From 119e16f06aa6c03eaef2adcb1d2685980efbf523 Mon Sep 17 00:00:00 2001 From: cbucher Date: Thu, 24 Feb 2011 10:38:36 +0100 Subject: [PATCH 070/207] bug fix : when scrollbars are enabled, their position is not properly setted. --- Console/ConsoleView.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 06dd6bf2..3c81e8fa 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -800,7 +800,7 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* */ InitializeScrollbars(); - RecreateOffscreenBuffers(); + RecreateOffscreenBuffers(); // notify parent about resize m_mainFrame.SendMessage(UM_CONSOLE_RESIZED, 0, 0); @@ -1511,8 +1511,8 @@ void ConsoleView::InitializeScrollbars() { SharedMemory& consoleParams = m_consoleHandler.GetConsoleParams(); - m_bShowVScroll = m_appearanceSettings.controlsSettings.bShowScrollbars && (consoleParams->dwBufferRows > consoleParams->dwRows); - m_bShowHScroll = m_appearanceSettings.controlsSettings.bShowScrollbars && (consoleParams->dwBufferColumns > consoleParams->dwColumns); + m_bShowVScroll = m_appearanceSettings.controlsSettings.bShowScrollbars && (consoleParams->dwBufferRows > consoleParams->dwRows); + m_bShowHScroll = m_appearanceSettings.controlsSettings.bShowScrollbars && (consoleParams->dwBufferColumns > consoleParams->dwColumns); // if (m_nScrollbarStyle != FSB_REGULAR_MODE) @@ -1526,8 +1526,8 @@ void ConsoleView::InitializeScrollbars() ::UninitializeFlatSB(m_hWnd); } - ::FlatSB_ShowScrollBar(m_hWnd, SB_VERT, m_bShowVScroll); - ::FlatSB_ShowScrollBar(m_hWnd, SB_HORZ, m_bShowHScroll); + ::FlatSB_ShowScrollBar(m_hWnd, SB_VERT, m_bShowVScroll); + ::FlatSB_ShowScrollBar(m_hWnd, SB_HORZ, m_bShowHScroll); /* TRACE(L"InitializeScrollbars, console wnd: 0x%08X\n", m_hWnd); @@ -1541,24 +1541,26 @@ void ConsoleView::InitializeScrollbars() SCROLLINFO si ; si.cbSize = sizeof(SCROLLINFO) ; - si.fMask = SIF_PAGE | SIF_RANGE ; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; si.nPage = consoleParams->dwRows; si.nMax = consoleParams->dwBufferRows - 1; si.nMin = 0 ; + si.nPos = m_consoleHandler.GetConsoleInfo()->csbi.srWindow.Top; ::FlatSB_SetScrollInfo(m_hWnd, SB_VERT, &si, TRUE); } if (m_appearanceSettings.controlsSettings.bShowScrollbars && (consoleParams->dwBufferColumns > consoleParams->dwColumns)) { - // set vertical scrollbar stuff + // set horizontal scrollbar stuff SCROLLINFO si ; si.cbSize = sizeof(SCROLLINFO) ; - si.fMask = SIF_PAGE | SIF_RANGE ; + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; si.nPage = consoleParams->dwColumns; si.nMax = consoleParams->dwBufferColumns - 1; si.nMin = 0 ; + si.nPos = m_consoleHandler.GetConsoleInfo()->csbi.srWindow.Left; ::FlatSB_SetScrollInfo(m_hWnd, SB_HORZ, &si, TRUE); } @@ -1589,7 +1591,7 @@ void ConsoleView::DoScroll(int nType, int nScrollCode, int nThumbPos) nDelta = (nType == SB_VERT) ? -static_cast(m_consoleHandler.GetConsoleParams()->dwRows) : -static_cast(m_consoleHandler.GetConsoleParams()->dwColumns); } break; - + case SB_PAGEDOWN: /* SB_PAGERIGHT */ if (scrollSettings.dwPageScrollRows > 0) { From 2834b41d0dc06a325f7fda939c5a8cf4a2ac5c13 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 5 Mar 2011 10:16:23 +0100 Subject: [PATCH 071/207] optimize --- Console/ConsoleView.cpp | 13 ++++--------- shared/Structures.h | 11 +++++++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 3c81e8fa..3df4a0cd 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -1322,11 +1322,7 @@ void ConsoleView::OnConsoleChange(bool bResize) // copy changed data for (DWORD dwOffset = 0; dwOffset < dwBufferSize; ++dwOffset) { - if (memcmp(&(m_screenBuffer[dwOffset].charInfo), &(consoleBuffer[dwOffset]), sizeof(CHAR_INFO))) - { - memcpy(&(m_screenBuffer[dwOffset].charInfo), &(consoleBuffer[dwOffset]), sizeof(CHAR_INFO)); - m_screenBuffer[dwOffset].changed = true; - } + m_screenBuffer[dwOffset].copy(consoleBuffer.Get() + dwOffset); } WPARAM wParam = 0; @@ -1740,7 +1736,7 @@ void ConsoleView::RepaintText(CDC& dc) } } - MutexLock bufferLock(m_consoleHandler.m_bufferMutex); + MutexLock bufferLock(m_consoleHandler.m_bufferMutex); DWORD dwX = m_nVInsideBorder; DWORD dwY = m_nHInsideBorder; @@ -1758,7 +1754,7 @@ void ConsoleView::RepaintText(CDC& dc) wstring strText(L""); - for (DWORD i = 0; i < m_dwScreenRows; ++i) + for (DWORD i = 0; i < m_dwScreenRows; ++i) { dwX = m_nVInsideBorder; dwY = i*m_nCharHeight + m_nHInsideBorder; @@ -1886,10 +1882,9 @@ void ConsoleView::RepaintTextChanges(CDC& dc) if (m_tabData->backgroundImageType != bktypeNone) g_imageHandler->UpdateImageBitmap(dc, rectWindow, m_background); - for (DWORD i = 0; i < m_dwScreenRows; ++i) + for (DWORD i = 0; i < m_dwScreenRows; ++i, dwY += m_nCharHeight) { dwX = m_nVInsideBorder; - dwY = i*m_nCharHeight + m_nHInsideBorder; for (DWORD j = 0; j < m_dwScreenColumns; ++j, ++dwOffset, dwX += m_nCharWidth) { diff --git a/shared/Structures.h b/shared/Structures.h index a06d5b62..27c8ec56 100644 --- a/shared/Structures.h +++ b/shared/Structures.h @@ -170,6 +170,17 @@ struct CharInfo *(reinterpret_cast(&charInfo)) = 0x00000020; } + inline void copy(CHAR_INFO* pnewCharInfo) + { + DWORD* pold = reinterpret_cast(&charInfo); + DWORD* pnew = reinterpret_cast(pnewCharInfo); + if( *pold != *pnew ) + { + *pold = *pnew; + changed = true; + } + } + CHAR_INFO charInfo; bool changed; }; From 7544dfbe9dd107995e5b56aabd593963f2c3e743 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 6 Mar 2011 08:44:05 +0100 Subject: [PATCH 072/207] show / hide menu with menu syskey (alt) --- Console/ConsoleView.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 3df4a0cd..fe4ab760 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -319,6 +319,12 @@ LRESULT ConsoleView::OnConsoleFwdMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BO { if (((uMsg == WM_KEYDOWN) || (uMsg == WM_KEYUP)) && (wParam == VK_PACKET)) return 0; + if (uMsg == WM_SYSKEYUP && wParam == VK_MENU) { + m_mainFrame.PostMessage(WM_COMMAND, ID_VIEW_MENU); + + return 0; + } + if (uMsg == WM_MOUSEWHEEL && wParam & MK_CONTROL) { short direction = HIWORD(wParam); From b3211726391720539a5a8b25da0e5f7c348dc053 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 20 Mar 2011 09:02:57 +0100 Subject: [PATCH 073/207] Quake style, hot key has 3 actions: - show if not visible - get focus if visible - hide if console has focus --- Console/MainFrame.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 1aeab1cd..27f767f2 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -423,11 +423,11 @@ LRESULT MainFrame::OnHotKey(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOO { if(!::IsWindowVisible(m_hWnd)) { - ::AnimateWindow(m_hWnd, 350, AW_ACTIVATE | AW_SLIDE | AW_VER_POSITIVE); + ::AnimateWindow(m_hWnd, 300, AW_ACTIVATE | AW_SLIDE | AW_VER_POSITIVE); } - else + else if(this->GetActiveView() == GetFocus()) { - ::AnimateWindow(m_hWnd, 350, AW_HIDE | AW_SLIDE | AW_VER_NEGATIVE); + ::AnimateWindow(m_hWnd, 300, AW_HIDE | AW_SLIDE | AW_VER_NEGATIVE); bActivate = false; } } From f7935f5d3c3187f28ac8cc8a3a0abc9d2818fbef Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 8 May 2011 09:53:52 +0200 Subject: [PATCH 074/207] inactive console will not display animation --- Console/Cursors.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Console/Cursors.cpp b/Console/Cursors.cpp index 1534d60d..26594d62 100644 --- a/Console/Cursors.cpp +++ b/Console/Cursors.cpp @@ -1064,10 +1064,8 @@ FadeBlockCursor::~FadeBlockCursor() ////////////////////////////////////////////////////////////////////////////// -void FadeBlockCursor::Draw(bool /*bActive*/ /* = true */) +void FadeBlockCursor::Draw(bool bActive /* = true */) { - m_dcCursor.FillRect(&m_rectCursor, m_paintBrush); -/* if (bActive) { m_dcCursor.FillRect(&m_rectCursor, m_paintBrush); @@ -1076,7 +1074,6 @@ void FadeBlockCursor::Draw(bool /*bActive*/ /* = true */) { m_dcCursor.FillRect(&m_rectCursor, m_backgroundBrush); } -*/ } ////////////////////////////////////////////////////////////////////////////// From 7fe154100f698ba5e092ba260d334cada326e950 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 8 May 2011 09:55:53 +0200 Subject: [PATCH 075/207] console activation will no longer loose the maximized state --- Console/MainFrame.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 27f767f2..69b96e99 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -433,7 +433,7 @@ LRESULT MainFrame::OnHotKey(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOO } else { - ShowWindow(SW_RESTORE); + ShowWindow(this->IsIconic()?SW_RESTORE:SW_SHOW); } if( bActivate ) @@ -2128,7 +2128,6 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole) AdjustWindowRect(clientRect); // TRACE(L"AdjustWindowSize: %ix%i\n", clientRect.Width(), clientRect.Height()); - SetWindowPos( 0, 0, From 590f8af390a06d99a1e3835aea6da57bc2738d6f Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 22 May 2011 15:59:48 +0200 Subject: [PATCH 076/207] code cleanify --- Console/MainFrame.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 69b96e99..b83dc5ef 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -93,7 +93,7 @@ BOOL MainFrame::OnIdle() UpdateStatusBar(); UIUpdateToolBar(); - if (m_activeView.get() != NULL) + if (m_activeView) { UIEnable(ID_EDIT_COPY, m_activeView->CanCopy() ? TRUE : FALSE); UIEnable(ID_EDIT_CLEAR_SELECTION, m_activeView->CanClearSelection() ? TRUE : FALSE); @@ -352,7 +352,7 @@ LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) { RemoveTab(it->second->m_hWnd); - if (m_activeView.get() == it->second.get()) m_activeView.reset(); + if (m_activeView == it->second) m_activeView.reset(); it->second->DestroyWindow(); } @@ -548,7 +548,7 @@ LRESULT MainFrame::OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& / if (!m_activeView) return 0; - + m_activeView->SetResizing(true); CPoint pointSize = m_activeView->GetCellSize(); @@ -661,7 +661,7 @@ LRESULT MainFrame::OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM } - if (m_activeView.get() != NULL) + if (m_activeView) { CRect rectClient; GetClientRect(&rectClient); @@ -1014,7 +1014,6 @@ LRESULT MainFrame::OnTabChanged(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) // clear the highlight in case it's on HighlightTab(m_activeView->m_hWnd, false); - } else { @@ -1024,7 +1023,7 @@ LRESULT MainFrame::OnTabChanged(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) if (appearanceSettings.stylesSettings.bTrayIcon) SetTrayIcon(NIM_MODIFY); - if (appearanceSettings.windowSettings.bUseTabTitles && (m_activeView.get() != NULL)) + if (appearanceSettings.windowSettings.bUseTabTitles && m_activeView) { SetWindowText(m_activeView->GetTitle()); } @@ -1421,7 +1420,7 @@ LRESULT MainFrame::OnViewTabs(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnViewConsole(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView.get() != NULL) + if (m_activeView) { m_activeView->SetConsoleWindowVisible(!m_activeView->GetConsoleWindowVisible()); UISetCheck(ID_VIEW_CONSOLE, m_activeView->GetConsoleWindowVisible() ? TRUE : FALSE); @@ -1657,7 +1656,7 @@ void MainFrame::CloseTab(HWND hwndConsoleView) if (it == m_views.end()) return; RemoveTab(hwndConsoleView); - if (m_activeView.get() == it->second.get()) m_activeView.reset(); + if (m_activeView == it->second) m_activeView.reset(); it->second->DestroyWindow(); m_views.erase(it); @@ -1928,7 +1927,7 @@ void MainFrame::SetWindowIcons() if (!m_icon.IsNull()) m_icon.DestroyIcon(); if (!m_smallIcon.IsNull()) m_smallIcon.DestroyIcon(); - if (windowSettings.bUseTabIcon && (m_activeView.get() != NULL)) + if (windowSettings.bUseTabIcon && m_activeView) { m_icon.Attach(m_activeView->GetIcon(true).DuplicateIcon()); m_smallIcon.Attach(m_activeView->GetIcon(false).DuplicateIcon()); @@ -2072,7 +2071,7 @@ void MainFrame::ResizeWindow() SendMessage(WM_NULL, 0, 0); m_dwResizeWindowEdge = WMSZ_BOTTOM; - if (m_activeView.get() != NULL) m_activeView->SetResizing(false); + if (m_activeView) m_activeView->SetResizing(false); } ////////////////////////////////////////////////////////////////////////////// @@ -2104,7 +2103,7 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole) for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) { - if (it->second->m_hWnd == m_activeView->m_hWnd) continue; + if (m_activeView == it->second) continue; it->second->SetWindowPos( 0, From 39ed72aefd9bffa6ba9ae1c981de2ff91265d572 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 28 May 2011 09:04:02 +0200 Subject: [PATCH 077/207] copy RTF to clipboard --- Console/SelectionHandler.cpp | 8 + Console/SelectionHandler.h | 8 +- ConsoleHook/ConsoleHandler.cpp | 301 +++++++++++++++++++++++++++++---- shared/Structures.h | 9 + 4 files changed, 286 insertions(+), 40 deletions(-) diff --git a/Console/SelectionHandler.cpp b/Console/SelectionHandler.cpp index 6708ac5f..5c7cb3b5 100644 --- a/Console/SelectionHandler.cpp +++ b/Console/SelectionHandler.cpp @@ -268,6 +268,14 @@ void SelectionHandler::CopySelection() m_consoleCopyInfo->bNoWrap = g_settingsHandler->GetBehaviorSettings().copyPasteSettings.bNoWrap; m_consoleCopyInfo->bTrimSpaces = g_settingsHandler->GetBehaviorSettings().copyPasteSettings.bTrimSpaces; m_consoleCopyInfo->copyNewlineChar= g_settingsHandler->GetBehaviorSettings().copyPasteSettings.copyNewlineChar; + _snprintf( + m_consoleCopyInfo->szFontName, sizeof(m_consoleCopyInfo->szFontName), + "%ws", + g_settingsHandler->GetAppearanceSettings().fontSettings.strName.c_str()); + m_consoleCopyInfo->bBold = g_settingsHandler->GetAppearanceSettings().fontSettings.bBold; + m_consoleCopyInfo->bItalic = g_settingsHandler->GetAppearanceSettings().fontSettings.bItalic; + m_consoleCopyInfo->dwSize = g_settingsHandler->GetAppearanceSettings().fontSettings.dwSize * 2; + ::CopyMemory(m_consoleCopyInfo->consoleColors, g_settingsHandler->GetConsoleSettings().consoleColors, sizeof(m_consoleCopyInfo->consoleColors)); m_consoleCopyInfo.SetReqEvent(); } diff --git a/Console/SelectionHandler.h b/Console/SelectionHandler.h index d43f4fe5..b57cb868 100644 --- a/Console/SelectionHandler.h +++ b/Console/SelectionHandler.h @@ -66,10 +66,10 @@ class SelectionHandler CRect m_rectConsoleView; - ConsoleHandler& m_consoleHandler; - SharedMemory& m_consoleParams; - SharedMemory& m_consoleInfo; - SharedMemory& m_consoleCopyInfo; + ConsoleHandler& m_consoleHandler; + SharedMemory& m_consoleParams; + SharedMemory& m_consoleInfo; + SharedMemory& m_consoleCopyInfo; int m_nCharWidth; int m_nCharHeight; int m_nVInsideBorder; diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index 175d90ef..a5ecccb6 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -450,6 +450,244 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD ////////////////////////////////////////////////////////////////////////////// +class ClipboardData +{ +public: + ClipboardData(void) {} + virtual ~ClipboardData(void) {} + virtual void StartRow(void) = 0; + virtual void EndRow(void) = 0; + virtual void AddChar(PCHAR_INFO) = 0; + virtual bool IsLastCharBlank(void) = 0; + virtual size_t GetRowLength(void) = 0; + virtual void TrimRight(void) = 0; + virtual void Wrap(CopyNewlineChar) = 0; + virtual void Publish(void) = 0; + + class Global + { + public: + Global(const void* p, size_t size) + { + hText = ::GlobalAlloc(GMEM_MOVEABLE, size); + if( hText ) + { + ::CopyMemory(::GlobalLock(hText), p, size); + ::GlobalUnlock(hText); + } + } + ~Global(void) + { + if( hText ) + { + // we need to global-free data only if copying failed + ::GlobalFree(hText); + } + } + HGLOBAL release(void) + { + HGLOBAL h = hText; + hText = NULL; + return h; + } + HGLOBAL get(void) const + { + return hText; + } + private: + HGLOBAL hText; + }; +}; + +class ClipboardDataUnicode : public ClipboardData +{ +public: + ClipboardDataUnicode(void):strText(L"") {} + virtual ~ClipboardDataUnicode(void) {} + virtual void StartRow(void) + { + strRow = L""; + } + virtual void EndRow(void) + { + strText += strRow; + } + virtual void AddChar(PCHAR_INFO p) + { + strRow += p->Char.UnicodeChar; + } + virtual bool IsLastCharBlank(void) + { + if( strRow.length() < 1 ) return false; + + return strRow[strRow.length() - 1] == L' '; + } + size_t GetRowLength(void) + { + return strRow.length(); + } + virtual void TrimRight(void) + { + trim_right(strRow); + } + virtual void Wrap(CopyNewlineChar copyNewlineChar) + { + switch(copyNewlineChar) + { + case newlineCRLF: strRow += wstring(L"\r\n"); break; + case newlineLF: strRow += wstring(L"\n"); break; + default: strRow += wstring(L"\r\n"); break; + } + } + virtual void Publish(void) + { + ClipboardData::Global global(strText.c_str(), (strText.length()+1)*sizeof(wchar_t)); + + if( !global.get() ) return; + + if( ::SetClipboardData(CF_UNICODETEXT, global.get()) ) + { + global.release(); + } + } + +private: + wstring strText; + wstring strRow; +}; + +class ClipboardDataRtf : public ClipboardData +{ +public: + ClipboardDataRtf(ConsoleCopy* pconsoleCopy):sizeRtfLen(0) + { + strRtf = "{\\rtf\\ansi\\deff0"; + + strRtf += "{\\fonttbl{\\f0\\fnil "; + strRtf += pconsoleCopy->szFontName; + strRtf += ";}}"; + + strRtf += "{\\colortbl\n"; + for(int i = 0; i < 16; i ++) + { + int red = (pconsoleCopy->consoleColors[i] >> 16) & 0xff; + int green = (pconsoleCopy->consoleColors[i] >> 8 ) & 0xff; + int blue = (pconsoleCopy->consoleColors[i] ) & 0xff; + char szColor[64]; + _snprintf( + szColor, sizeof(szColor), + "\\red%lu\\green%lu\\blue%lu;\n", + GetRValue(pconsoleCopy->consoleColors[i]), + GetGValue(pconsoleCopy->consoleColors[i]), + GetBValue(pconsoleCopy->consoleColors[i])); + strRtf += szColor; + } + strRtf += "}"; + + char szFont[64]; + _snprintf( + szFont, sizeof(szFont), + "\\f0\\fs%lu%s%s\n", + pconsoleCopy->dwSize, + pconsoleCopy->bBold ? "\\b" : "", + pconsoleCopy->bItalic ? "\\i" : ""); + + strRtf += szFont; + } + virtual ~ClipboardDataRtf(void) {} + virtual void StartRow(void) + { + strRow = ""; + sizeRowLen = 0; + } + virtual void EndRow(void) + { + strRtf += strRow; + } + virtual void AddChar(PCHAR_INFO p) + { + char szDummy[32]; + + WORD wCharForegroundAttributes = p->Attributes & 0x000f; + WORD wCharBackgroundAttributes = (p->Attributes >> 4) & 0x000f; + if( sizeRtfLen == 0 ) + { + wLastCharForegroundAttributes = ~wCharForegroundAttributes; + wLastCharBackgroundAttributes = ~wCharBackgroundAttributes; + } + if( wLastCharBackgroundAttributes != wCharBackgroundAttributes ) + { + _snprintf( + szDummy, sizeof(szDummy), + "\\highlight%hu ", + wCharBackgroundAttributes); + strRow += szDummy; + } + if( wLastCharForegroundAttributes != wCharForegroundAttributes ) + { + _snprintf( + szDummy, sizeof(szDummy), + "\\cf%hu ", + wCharForegroundAttributes); + strRow += szDummy; + } + wLastCharForegroundAttributes = wCharForegroundAttributes; + wLastCharBackgroundAttributes = wCharBackgroundAttributes; + + WCHAR wc = p->Char.UnicodeChar; + if( wc == L'\\' ) strRow += "\\\\"; + else if( wc == L'{' ) strRow += "\\{"; + else if( wc == L'}' ) strRow += "\\}"; + else if( wc <= 0x7f ) strRow += p->Char.AsciiChar; + else + { + _snprintf(szDummy, sizeof(szDummy), "\\u%d?", wc); + strRow += szDummy; + } + sizeRowLen ++; + sizeRtfLen ++; + } + virtual bool IsLastCharBlank(void) + { + if( strRow.length() < 1 ) return false; + + return strRow[strRow.length() - 1] == ' '; + } + size_t GetRowLength(void) + { + return sizeRowLen; + } + virtual void TrimRight(void) + { + trim_right(strRow); + } + virtual void Wrap(CopyNewlineChar /*copyNewlineChar*/) + { + strRow += "\\line\n"; + } + virtual void Publish(void) + { + strRtf += "}"; + + ClipboardData::Global global(strRtf.c_str(), strRtf.length() + 1); + + if( !global.get() ) return; + + if( ::SetClipboardData(::RegisterClipboardFormat(L"Rich Text Format"), global.get()) ) + { + global.release(); + } + } + +private: + string strRtf; + string strRow; + size_t sizeRtfLen; + size_t sizeRowLen; + WORD wLastCharForegroundAttributes; + WORD wLastCharBackgroundAttributes; +}; + void ConsoleHandler::CopyConsoleText() { if (!::OpenClipboard(NULL)) return; @@ -470,9 +708,13 @@ void ConsoleHandler::CopyConsoleText() 0), ::CloseHandle); + auto_ptr clipboardDataPtr[2]; + size_t clipboardDataCount = 2; + clipboardDataPtr[0].reset(new ClipboardDataUnicode()); + clipboardDataPtr[1].reset(new ClipboardDataRtf(m_consoleCopyInfo.Get())); + // get total console size CONSOLE_SCREEN_BUFFER_INFO csbiConsole; - wstring strText(L""); ::GetConsoleScreenBufferInfo(hStdOut.get(), &csbiConsole); @@ -502,13 +744,16 @@ void ConsoleHandler::CopyConsoleText() // TRACE(L"Read region: (%i, %i) - (%i, %i)\n", srBuffer.Left, srBuffer.Top, srBuffer.Right, srBuffer.Bottom); - wstring strRow(L""); + for(size_t clipboardDataIndex = 0; clipboardDataIndex < clipboardDataCount; clipboardDataIndex ++) + clipboardDataPtr[clipboardDataIndex]->StartRow(); + bool bWrap = true; for (SHORT x = 0; x <= srBuffer.Right - srBuffer.Left; ++x) { if (pScreenBuffer[x].Attributes & COMMON_LVB_TRAILING_BYTE) continue; - strRow += pScreenBuffer[x].Char.UnicodeChar; + for(size_t clipboardDataIndex = 0; clipboardDataIndex < clipboardDataCount; clipboardDataIndex ++) + clipboardDataPtr[clipboardDataIndex]->AddChar(&(pScreenBuffer[x])); } // handle trim/wrap settings @@ -524,7 +769,7 @@ void ConsoleHandler::CopyConsoleText() && (coordStart.Y < coordEnd.Y) && - (strRow[strRow.length() - 1] != L' ') + (!clipboardDataPtr[0]->IsLastCharBlank()) ) ) { @@ -534,7 +779,7 @@ void ConsoleHandler::CopyConsoleText() else if (i == coordEnd.Y) { // last row - if (strRow.length() < static_cast(coordBufferSize.X)) + if (clipboardDataPtr[0]->GetRowLength() < static_cast(coordBufferSize.X)) { bWrap = false; } @@ -542,47 +787,31 @@ void ConsoleHandler::CopyConsoleText() else { // rows in between - if (m_consoleCopyInfo->bNoWrap && (strRow[strRow.length() - 1] != L' ')) + if (m_consoleCopyInfo->bNoWrap && (!clipboardDataPtr[0]->IsLastCharBlank())) { bWrap = false; } } - if (m_consoleCopyInfo->bTrimSpaces) trim_right(strRow); - if (bWrap) - { - switch(m_consoleCopyInfo->copyNewlineChar) - { - case newlineCRLF: strRow += wstring(L"\r\n"); break; - case newlineLF : strRow += wstring(L"\n"); break; - default : strRow += wstring(L"\r\n"); break; - } - } - - strText += strRow; - } + for(size_t clipboardDataIndex = 0; clipboardDataIndex < clipboardDataCount; clipboardDataIndex ++) + { + if (m_consoleCopyInfo->bTrimSpaces) + clipboardDataPtr[clipboardDataIndex]->TrimRight(); - ::EmptyClipboard(); + if (bWrap) + clipboardDataPtr[clipboardDataIndex]->Wrap(m_consoleCopyInfo->copyNewlineChar); - HGLOBAL hText = ::GlobalAlloc(GMEM_MOVEABLE, (strText.length()+1)*sizeof(wchar_t)); + clipboardDataPtr[clipboardDataIndex]->EndRow(); + } + } - if (hText == NULL) - { - ::CloseClipboard(); - return; - } + ::EmptyClipboard(); - ::CopyMemory(static_cast(::GlobalLock(hText)), strText.c_str(), (strText.length()+1)*sizeof(wchar_t)); + for(size_t clipboardDataIndex = 0; clipboardDataIndex < clipboardDataCount; clipboardDataIndex ++) + clipboardDataPtr[clipboardDataIndex]->Publish(); - ::GlobalUnlock(hText); - - if (::SetClipboardData(CF_UNICODETEXT, hText) == NULL) - { - // we need to global-free data only if copying failed - ::GlobalFree(hText); - } - ::CloseClipboard(); - // !!! No call to GlobalFree here. Next app that uses clipboard will call EmptyClipboard to free the data + ::CloseClipboard(); + // !!! No call to GlobalFree here. Next app that uses clipboard will call EmptyClipboard to free the data } ////////////////////////////////////////////////////////////////////////////// diff --git a/shared/Structures.h b/shared/Structures.h index 27c8ec56..69963d76 100644 --- a/shared/Structures.h +++ b/shared/Structures.h @@ -115,7 +115,11 @@ struct ConsoleCopy , bNoWrap(false) , bTrimSpaces(false) , copyNewlineChar(newlineCRLF) + , bBold(false) + , bItalic(false) + , dwSize(24) { + szFontName[0] = 0; } COORD coordStart; @@ -123,6 +127,11 @@ struct ConsoleCopy bool bNoWrap; bool bTrimSpaces; CopyNewlineChar copyNewlineChar; + bool bBold; + bool bItalic; + DWORD dwSize; + char szFontName [256]; + COLORREF consoleColors[16]; }; From 5afc382b1cef8d7e52f6bcf22f8a38adc740a0d2 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 2 Jul 2011 09:17:55 +0200 Subject: [PATCH 078/207] remove ConsoleView::SetResizing --- Console/ConsoleView.cpp | 12 ++---------- Console/ConsoleView.h | 1 - Console/MainFrame.cpp | 4 ---- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index fe4ab760..118c6c46 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -234,6 +234,7 @@ LRESULT ConsoleView::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ LRESULT ConsoleView::OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { + m_bResizing = true; return 1; } @@ -262,6 +263,7 @@ LRESULT ConsoleView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ if (m_bResizing) { dc.FillRect(&dc.m_ps.rcPaint, m_backgroundBrush); + m_bResizing = false; } dc.BitBlt( @@ -1140,16 +1142,6 @@ void ConsoleView::MainframeMoving() ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -void ConsoleView::SetResizing(bool bResizing) -{ - m_bResizing = bResizing; -} - -////////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////////// void ConsoleView::SetActive(bool bActive) diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index ddad483b..566a1a68 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -116,7 +116,6 @@ class ConsoleView void Repaint(bool bFullRepaint); void MainframeMoving(); - void SetResizing(bool bResizing); void SetActive(bool bActive); void SetTitle(const CString& strTitle); const CString& GetTitle() const { return m_strTitle; } diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index b83dc5ef..2669283f 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -549,8 +549,6 @@ LRESULT MainFrame::OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& / if (!m_activeView) return 0; - m_activeView->SetResizing(true); - CPoint pointSize = m_activeView->GetCellSize(); RECT *rectNew = (RECT *)lParam; @@ -2070,8 +2068,6 @@ void MainFrame::ResizeWindow() SendMessage(WM_NULL, 0, 0); m_dwResizeWindowEdge = WMSZ_BOTTOM; - - if (m_activeView) m_activeView->SetResizing(false); } ////////////////////////////////////////////////////////////////////////////// From ddbb87ca12f7aa033bf230f305dce15b78cfbea3 Mon Sep 17 00:00:00 2001 From: cbucher Date: Mon, 8 Aug 2011 06:32:06 +0200 Subject: [PATCH 079/207] add TabView add multisplit del strDbgCmdLine --- Console/Console.cpp | 19 +- Console/Console.vcproj | 8 + Console/ConsoleHandler.cpp | 13 +- Console/ConsoleHandler.h | 13 +- Console/ConsoleView.cpp | 93 ++-- Console/ConsoleView.h | 19 +- Console/MainFrame.cpp | 517 ++++++++---------- Console/MainFrame.h | 24 +- Console/TabView.cpp | 298 ++++++++++ Console/TabView.h | 71 +++ Console/stdafx.h | 1 + ConsoleHook/ConsoleHandler.cpp | 17 +- wtl/wtl/include/multisplit.h | 960 +++++++++++++++++++++++++++++++++ 13 files changed, 1639 insertions(+), 414 deletions(-) create mode 100644 Console/TabView.cpp create mode 100644 Console/TabView.h create mode 100644 wtl/wtl/include/multisplit.h diff --git a/Console/Console.cpp b/Console/Console.cpp index 348ffe7e..9a185698 100644 --- a/Console/Console.cpp +++ b/Console/Console.cpp @@ -68,8 +68,7 @@ void ParseCommandLine vector& startupTabs, vector& startupDirs, vector& startupCmds, - int& nMultiStartSleep, - wstring& /*strDbgCmdLine*/ + int& nMultiStartSleep ) { int argc = 0; @@ -122,16 +121,6 @@ void ParseCommandLine nMultiStartSleep = _wtoi(argv[i]); if (nMultiStartSleep < 0) nMultiStartSleep = 500; } - // TODO: not working yet, need to investigate -/* - else if (wstring(argv[i]) == wstring(L"-dbg")) - { - // console window replacement option (see Tip 1 in the help file) - ++i; - if (i == argc) break; - strDbgCmdLine = argv[i]; - } -*/ } // make sure that startupDirs and startupCmds are at least as big as startupTabs @@ -155,7 +144,6 @@ int Run(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWDEFAULT) vector startupDirs; vector startupCmds; int nMultiStartSleep = 0; - wstring strDbgCmdLine(L""); ParseCommandLine( lpstrCmdLine, @@ -164,8 +152,7 @@ int Run(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWDEFAULT) startupTabs, startupDirs, startupCmds, - nMultiStartSleep, - strDbgCmdLine); + nMultiStartSleep); if (strConfigFile.length() == 0) { @@ -182,7 +169,7 @@ int Run(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWDEFAULT) // create main window NoTaskbarParent noTaskbarParent; - MainFrame wndMain(strWindowTitle, startupTabs, startupDirs, startupCmds, nMultiStartSleep, strDbgCmdLine); + MainFrame wndMain(strWindowTitle, startupTabs, startupDirs, startupCmds, nMultiStartSleep); if (!g_settingsHandler->GetAppearanceSettings().stylesSettings.bTaskbarButton) { diff --git a/Console/Console.vcproj b/Console/Console.vcproj index 9bc6e375..2bdab2cf 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -708,6 +708,10 @@ /> + + @@ -845,6 +849,10 @@ RelativePath="..\shared\Structures.h" > + + diff --git a/Console/ConsoleHandler.cpp b/Console/ConsoleHandler.cpp index ad342a0a..6ecad938 100644 --- a/Console/ConsoleHandler.cpp +++ b/Console/ConsoleHandler.cpp @@ -77,15 +77,14 @@ void ConsoleHandler::SetupDelegates(ConsoleChangeDelegate consoleChangeDelegate, bool ConsoleHandler::StartShellProcess ( - const wstring& strCustomShell, - const wstring& strInitialDir, + const wstring& strCustomShell, + const wstring& strInitialDir, const wstring& strUser, const wstring& strPassword, - const wstring& strInitialCmd, - const wstring& strConsoleTitle, - DWORD dwStartupRows, - DWORD dwStartupColumns, - bool /*bDebugFlag*/ + const wstring& strInitialCmd, + const wstring& strConsoleTitle, + DWORD dwStartupRows, + DWORD dwStartupColumns ) { wstring strUsername(strUser); diff --git a/Console/ConsoleHandler.h b/Console/ConsoleHandler.h index fdff9809..193aa2c8 100644 --- a/Console/ConsoleHandler.h +++ b/Console/ConsoleHandler.h @@ -54,15 +54,14 @@ class ConsoleHandler void SetupDelegates(ConsoleChangeDelegate consoleChangeDelegate, ConsoleCloseDelegate consoleCloseDelegate); bool StartShellProcess ( - const wstring& strCustomShell, - const wstring& strInitialDir, + const wstring& strCustomShell, + const wstring& strInitialDir, const wstring& strUser, const wstring& strPassword, - const wstring& strInitialCmd, - const wstring& strConsoleTitle, - DWORD dwStartupRows, - DWORD dwStartupColumns, - bool bDebugFlag + const wstring& strInitialCmd, + const wstring& strConsoleTitle, + DWORD dwStartupRows, + DWORD dwStartupColumns ); DWORD StartMonitorThread(); diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index fe4ab760..b133a120 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -4,9 +4,9 @@ #include #include "Console.h" -#include "MainFrame.h" #include "ConsoleException.h" #include "ConsoleView.h" +#include "MainFrame.h" ////////////////////////////////////////////////////////////////////////////// @@ -25,17 +25,13 @@ CFont ConsoleView::m_fontText; int ConsoleView::m_nCharHeight(0); int ConsoleView::m_nCharWidth(0); -int ConsoleView::m_nVInsideBorder(0); -int ConsoleView::m_nHInsideBorder(0); ////////////////////////////////////////////////////////////////////////////// -ConsoleView::ConsoleView(MainFrame& mainFrame, DWORD dwTabIndex, const wstring& strCmdLineInitialDir, const wstring& strInitialCmd, const wstring& strDbgCmdLine, DWORD dwRows, DWORD dwColumns) +ConsoleView::ConsoleView(MainFrame& mainFrame, HWND hwndTabView, shared_ptr tabData, const CString& strTitle, DWORD dwRows, DWORD dwColumns) : m_mainFrame(mainFrame) -, m_strCmdLineInitialDir(strCmdLineInitialDir) -, m_strInitialCmd(strInitialCmd) -, m_strDbgCmdLine(strDbgCmdLine) +, m_hwndTabView(hwndTabView) , m_bInitializing(true) , m_bResizing(false) , m_bAppActive(true) @@ -49,10 +45,10 @@ ConsoleView::ConsoleView(MainFrame& mainFrame, DWORD dwTabIndex, const wstring& , m_bShowHScroll(false) , m_nVScrollWidth(::GetSystemMetrics(SM_CXVSCROLL)) , m_nHScrollWidth(::GetSystemMetrics(SM_CXHSCROLL)) -, m_strTitle(g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]->strTitle.c_str()) +, m_nVInsideBorder(0) +, m_nHInsideBorder(0) +, m_strTitle(strTitle) , m_strUser() -, bigIcon() -, smallIcon() , m_consoleHandler() , m_screenBuffer() , m_dwScreenRows(0) @@ -60,7 +56,7 @@ ConsoleView::ConsoleView(MainFrame& mainFrame, DWORD dwTabIndex, const wstring& , m_consoleSettings(g_settingsHandler->GetConsoleSettings()) , m_appearanceSettings(g_settingsHandler->GetAppearanceSettings()) , m_hotkeys(g_settingsHandler->GetHotKeys()) -, m_tabData(g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]) +, m_tabData(tabData) , m_background() , m_backgroundBrush(NULL) , m_cursor() @@ -115,13 +111,9 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B { DragAcceptFiles(TRUE); - // load icon - bigIcon.Attach(Helpers::LoadTabIcon(true, m_tabData->bUseDefaultIcon, m_tabData->strIcon, m_tabData->strShell)); - smallIcon.Attach(Helpers::LoadTabIcon(false, m_tabData->bUseDefaultIcon, m_tabData->strIcon, m_tabData->strShell)); - // set console delegates m_consoleHandler.SetupDelegates( - fastdelegate::MakeDelegate(this, &ConsoleView::OnConsoleChange), + fastdelegate::MakeDelegate(this, &ConsoleView::OnConsoleChange), fastdelegate::MakeDelegate(this, &ConsoleView::OnConsoleClose)); // load background image @@ -149,14 +141,8 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B } wstring strShell(m_consoleSettings.strShell); - bool bDebugFlag = false; - if (m_strDbgCmdLine.length() > 0) - { - strShell = m_strDbgCmdLine; - bDebugFlag = true; - } - else if (m_tabData->strShell.length() > 0) + if (m_tabData->strShell.length() > 0) { strShell = m_tabData->strShell; } @@ -167,15 +153,14 @@ LRESULT ConsoleView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B UserCredentials* userCredentials = reinterpret_cast(createStruct->lpCreateParams); m_consoleHandler.StartShellProcess( - strShell, + strShell, strInitialDir, userCredentials->user, userCredentials->password, m_strInitialCmd, g_settingsHandler->GetAppearanceSettings().windowSettings.bUseConsoleTitle ? m_tabData->strTitle : wstring(L""), - m_dwStartupRows, - m_dwStartupColumns, - bDebugFlag); + m_dwStartupRows, + m_dwStartupColumns); m_strUser = userCredentials->user.c_str(); } @@ -702,12 +687,12 @@ LRESULT ConsoleView::OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BO return 0; } - m_mainFrame.HighlightTab(m_hWnd, (m_dwFlashes % 2) == 0); + m_mainFrame.HighlightTab(m_hwndTabView, (m_dwFlashes % 2) == 0); if (++m_dwFlashes == g_settingsHandler->GetBehaviorSettings().tabHighlightSettings.dwFlashes * 2) { if (g_settingsHandler->GetBehaviorSettings().tabHighlightSettings.bStayHighlighted) { - m_mainFrame.HighlightTab(m_hWnd, true); + m_mainFrame.HighlightTab(m_hwndTabView, true); } KillTimer(FLASH_TAB_TIMER); @@ -980,10 +965,8 @@ void ConsoleView::GetRect(CRect& clientRect) ////////////////////////////////////////////////////////////////////////////// -void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge, bool bVariableInsideBorder) +void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge) { - StylesSettings& stylesSettings = g_settingsHandler->GetAppearanceSettings().stylesSettings; - GetWindowRect(&clientRect); /* TRACE(L"================================================================\n"); @@ -996,15 +979,6 @@ void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdg if (m_bShowVScroll) width -= m_nVScrollWidth; if (m_bShowHScroll) height -= m_nHScrollWidth; - // exclude inside borders from row/col calculation - if (!bVariableInsideBorder) - { - m_nVInsideBorder = stylesSettings.dwInsideBorder; - m_nHInsideBorder = stylesSettings.dwInsideBorder; - width -= (m_nVInsideBorder * 2); - height -= (m_nHInsideBorder * 2); - } - DWORD dwColumns = width / m_nCharWidth; DWORD dwRows = height / m_nCharHeight; @@ -1017,11 +991,8 @@ void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdg dwRows = dwMaxRows; // variable inside borders - if (bVariableInsideBorder) - { - m_nVInsideBorder = (width - dwColumns * m_nCharWidth ) / 2; - m_nHInsideBorder = (height - dwRows * m_nCharHeight) / 2; - } + m_nVInsideBorder = (width - dwColumns * m_nCharWidth ) / 2; + m_nHInsideBorder = (height - dwRows * m_nCharHeight) / 2; clientRect.right = clientRect.left + dwColumns * m_nCharWidth + m_nVInsideBorder * 2; clientRect.bottom = clientRect.top + dwRows * m_nCharHeight + m_nHInsideBorder * 2; @@ -1083,8 +1054,8 @@ void ConsoleView::SetAppActiveStatus(bool bAppActive) void ConsoleView::RecreateFont() { - if (!m_fontText.IsNull()) m_fontText.DeleteObject(); - if (!CreateFont(m_appearanceSettings.fontSettings.strName)) + if (!m_fontText.IsNull()) m_fontText.DeleteObject(); + if (!CreateFont(g_settingsHandler->GetAppearanceSettings().fontSettings.strName)) { CreateFont(wstring(L"Courier New")); } @@ -1351,7 +1322,7 @@ void ConsoleView::OnConsoleChange(bool bResize) void ConsoleView::OnConsoleClose() { - if (::IsWindow(m_hWnd)) m_mainFrame.PostMessage(UM_CONSOLE_CLOSED, reinterpret_cast(m_hWnd), 0); + if (::IsWindow(m_hWnd)) m_mainFrame.PostMessage(UM_CONSOLE_CLOSED, reinterpret_cast(m_hwndTabView), 0); } ////////////////////////////////////////////////////////////////////////////// @@ -1460,20 +1431,20 @@ bool ConsoleView::CreateFont(const wstring& strFontName) BYTE byFontQuality = DEFAULT_QUALITY; - switch (m_appearanceSettings.fontSettings.fontSmoothing) + switch (g_settingsHandler->GetAppearanceSettings().fontSettings.fontSmoothing) { - case fontSmoothDefault : byFontQuality = DEFAULT_QUALITY; break; - case fontSmoothNone : byFontQuality = NONANTIALIASED_QUALITY; break; - case fontSmoothCleartype: byFontQuality = CLEARTYPE_QUALITY; break; + case fontSmoothDefault: byFontQuality = DEFAULT_QUALITY; break; + case fontSmoothNone: byFontQuality = NONANTIALIASED_QUALITY; break; + case fontSmoothCleartype: byFontQuality = CLEARTYPE_QUALITY; break; default : DEFAULT_QUALITY; } m_fontText.CreateFont( - -::MulDiv(m_appearanceSettings.fontSettings.dwSize , m_dcText.GetDeviceCaps(LOGPIXELSY), 72), + -::MulDiv(g_settingsHandler->GetAppearanceSettings().fontSettings.dwSize , m_dcText.GetDeviceCaps(LOGPIXELSY), 72), 0, 0, 0, - m_appearanceSettings.fontSettings.bBold ? FW_BOLD : 0, - m_appearanceSettings.fontSettings.bItalic, + g_settingsHandler->GetAppearanceSettings().fontSettings.bBold ? FW_BOLD : 0, + g_settingsHandler->GetAppearanceSettings().fontSettings.bItalic, FALSE, FALSE, DEFAULT_CHARSET, @@ -1495,12 +1466,12 @@ bool ConsoleView::CreateFont(const wstring& strFontName) } // fixed pitch font (TMPF_FIXED_PITCH is cleared!!!) - m_nCharWidth = textMetric.tmAveCharWidth; + m_nCharWidth = textMetric.tmAveCharWidth; m_nCharHeight = textMetric.tmHeight; - +#if 0 m_nVInsideBorder = g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder; m_nHInsideBorder = g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder; - +#endif return true; } @@ -1681,8 +1652,8 @@ void ConsoleView::UpdateTitle() } m_mainFrame.PostMessage( - UM_UPDATE_TITLES, - reinterpret_cast(m_hWnd), + UM_UPDATE_TITLES, + reinterpret_cast(m_hwndTabView), 0); } diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index ddad483b..dd5fe551 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -29,7 +29,7 @@ class ConsoleView DECLARE_WND_CLASS_EX(L"Console_2_View", CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS, COLOR_WINDOW) // DECLARE_WND_CLASS_EX(L"Console_2_View", CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, COLOR_WINDOW) - ConsoleView(MainFrame& mainFrame, DWORD dwTabIndex, const wstring& strCmdLineInitialDir, const wstring& strInitialCmd, const wstring& strDbgCmdLine, DWORD dwRows, DWORD dwColumns); + ConsoleView(MainFrame& mainFrame, HWND hwndTabView, shared_ptr tabData, const CString& strTitle, DWORD dwRows, DWORD dwColumns); ~ConsoleView(); BOOL PreTranslateMessage(MSG* pMsg); @@ -100,7 +100,7 @@ class ConsoleView public: void GetRect(CRect& clientRect); - void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge, bool bVariableInsideBorder); + void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge); CPoint GetCellSize() { return CPoint(m_nCharWidth, m_nCharHeight); }; ConsoleHandler& GetConsoleHandler() { return m_consoleHandler; } @@ -111,7 +111,7 @@ class ConsoleView void SetAppActiveStatus(bool bAppActive); - void RecreateFont(); + static void RecreateFont(); void RecreateOffscreenBuffers(); void Repaint(bool bFullRepaint); void MainframeMoving(); @@ -122,7 +122,6 @@ class ConsoleView const CString& GetTitle() const { return m_strTitle; } CString GetConsoleCommand(); - CIcon& GetIcon(bool bBigIcon = true) { return bBigIcon ? bigIcon : smallIcon; } void Copy(const CPoint* pPoint = NULL); void ClearSelection(); @@ -144,7 +143,7 @@ class ConsoleView void CreateOffscreenBuffers(); void CreateOffscreenBitmap(CDC& cdc, const CRect& rect, CBitmap& bitmap); - bool CreateFont(const wstring& strFontName); + static bool CreateFont(const wstring& strFontName); void DoScroll(int nType, int nScrollCode, int nThumbPos); @@ -170,10 +169,10 @@ class ConsoleView private: MainFrame& m_mainFrame; + HWND m_hwndTabView; wstring m_strCmdLineInitialDir; wstring m_strInitialCmd; - wstring m_strDbgCmdLine; bool m_bInitializing; bool m_bResizing; @@ -190,14 +189,12 @@ class ConsoleView bool m_bShowHScroll; int m_nVScrollWidth; int m_nHScrollWidth; + int m_nVInsideBorder; + int m_nHInsideBorder; CString m_strTitle; CString m_strUser; - CIcon bigIcon; - CIcon smallIcon; - - ConsoleHandler m_consoleHandler; shared_array m_screenBuffer; @@ -239,8 +236,6 @@ class ConsoleView static int m_nCharHeight; static int m_nCharWidth; - static int m_nVInsideBorder; - static int m_nHInsideBorder; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index b83dc5ef..4ab94347 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -3,11 +3,11 @@ #include "aboutdlg.h" #include "Console.h" +#include "TabView.h" #include "ConsoleView.h" #include "ConsoleException.h" #include "DlgRenameTab.h" #include "DlgSettingsMain.h" -#include "DlgCredentials.h" #include "MainFrame.h" ////////////////////////////////////////////////////////////////////////////// @@ -23,19 +23,17 @@ MainFrame::MainFrame ( const wstring strWindowTitle, - const vector& startupTabs, - const vector& startupDirs, - const vector& startupCmds, - int nMultiStartSleep, - const wstring& strDbgCmdLine + const vector& startupTabs, + const vector& startupDirs, + const vector& startupCmds, + int nMultiStartSleep ) : m_bOnCreateDone(false) , m_startupTabs(startupTabs) , m_startupDirs(startupDirs) , m_startupCmds(startupCmds) , m_nMultiStartSleep(nMultiStartSleep) -, m_strDbgCmdLine(strDbgCmdLine) -, m_activeView() +, m_activeTabView() , m_bMenuVisible(TRUE) , m_bToolbarVisible(TRUE) , m_bStatusBarVisible(TRUE) @@ -43,12 +41,10 @@ MainFrame::MainFrame , m_dockPosition(dockNone) , m_zOrder(zorderNormal) , m_mousedragOffset(0, 0) -, m_views() -, m_viewsMutex(NULL, FALSE, NULL) +, m_tabs() +, m_tabsMutex(NULL, FALSE, NULL) , m_strCmdLineWindowTitle(strWindowTitle.c_str()) , m_strWindowTitle(strWindowTitle.c_str()) -, m_dwRows(0) -, m_dwColumns(0) , m_dwWindowWidth(0) , m_dwWindowHeight(0) , m_dwResizeWindowEdge(WMSZ_BOTTOM) @@ -78,9 +74,9 @@ BOOL MainFrame::PreTranslateMessage(MSG* pMsg) if(CTabbedFrameImpl::PreTranslateMessage(pMsg)) return TRUE; - if (!m_activeView) return FALSE; + if (!m_activeTabView) return FALSE; - return m_activeView->PreTranslateMessage(pMsg); + return m_activeTabView->PreTranslateMessage(pMsg); } ////////////////////////////////////////////////////////////////////////////// @@ -90,17 +86,22 @@ BOOL MainFrame::PreTranslateMessage(MSG* pMsg) BOOL MainFrame::OnIdle() { - UpdateStatusBar(); - UIUpdateToolBar(); + UpdateStatusBar(); + UIUpdateToolBar(); - if (m_activeView) - { - UIEnable(ID_EDIT_COPY, m_activeView->CanCopy() ? TRUE : FALSE); - UIEnable(ID_EDIT_CLEAR_SELECTION, m_activeView->CanClearSelection() ? TRUE : FALSE); - UIEnable(ID_EDIT_PASTE, m_activeView->CanPaste() ? TRUE : FALSE); - } + if (m_activeTabView) + { + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + UIEnable(ID_EDIT_COPY, activeConsoleView->CanCopy() ? TRUE : FALSE); + UIEnable(ID_EDIT_CLEAR_SELECTION, activeConsoleView->CanClearSelection() ? TRUE : FALSE); + UIEnable(ID_EDIT_PASTE, activeConsoleView->CanPaste() ? TRUE : FALSE); + UISetCheck(ID_VIEW_CONSOLE, activeConsoleView->GetConsoleWindowVisible() ? TRUE : FALSE); + } + } - return FALSE; + return FALSE; } ////////////////////////////////////////////////////////////////////////////// @@ -167,7 +168,7 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, DWORD dwTabStyles = CTCS_TOOLTIPS | CTCS_DRAGREARRANGE | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_HOTTRACK; if (controlsSettings.bTabsOnBottom) dwTabStyles |= CTCS_BOTTOM; - + CreateTabWindow(m_hWnd, rcDefault, dwTabStyles); // create initial console window(s) @@ -179,7 +180,7 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, if (m_startupDirs.size() > 0) strStartupDir = m_startupDirs[0]; if (m_startupCmds.size() > 0) strStartupCmd = m_startupCmds[0]; - if (!CreateNewConsole(0, strStartupDir, strStartupCmd, m_strDbgCmdLine)) return -1; + if (!CreateNewConsole(0, strStartupDir, strStartupCmd)) return -1; } else { @@ -196,10 +197,9 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, { // found it, create if (CreateNewConsole( - static_cast(i), + static_cast(i), m_startupDirs[tabIndex], - m_startupCmds[tabIndex], - (i == 0) ? m_strDbgCmdLine : wstring(L""))) + m_startupCmds[tabIndex])) { bAtLeastOneStarted = true; } @@ -228,12 +228,12 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, ShowTabs(controlsSettings.bShowTabs ? TRUE : FALSE); { - MutexLock lock(m_viewsMutex); - if (m_views.size() == 1) + MutexLock lock(m_tabsMutex); + if (m_tabs.size() == 1) { UIEnable(ID_FILE_CLOSE_TAB, FALSE); } - if ((m_views.size() == 1) && m_bTabsVisible && (controlsSettings.bHideSingleTab)) + if ((m_tabs.size() == 1) && m_bTabsVisible && (controlsSettings.bHideSingleTab)) { ShowTabs(FALSE); } @@ -317,7 +317,7 @@ LRESULT MainFrame::OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPara LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { - if( m_views.size() > 1 && (::MessageBox(m_hWnd, L"Are you sure you want close all tabs ?", L"Close", MB_OKCANCEL | MB_ICONQUESTION) == IDCANCEL) ) + if( m_tabs.size() > 1 && (::MessageBox(m_hWnd, L"Are you sure you want close all tabs ?", L"Close", MB_OKCANCEL | MB_ICONQUESTION) == IDCANCEL) ) return 0; // save settings on exit @@ -327,9 +327,10 @@ LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, if (consoleSettings.bSaveSize) { +#if 0 consoleSettings.dwRows = m_dwRows; consoleSettings.dwColumns = m_dwColumns; - +#endif bSaveSettings = true; } @@ -348,11 +349,11 @@ LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, if (bSaveSettings) g_settingsHandler->SaveSettings(); // destroy all views - MutexLock viewMapLock(m_viewsMutex); - for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + MutexLock viewMapLock(m_tabsMutex); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) { RemoveTab(it->second->m_hWnd); - if (m_activeView == it->second) m_activeView.reset(); + if (m_activeTabView == it->second) m_activeTabView.reset(); it->second->DestroyWindow(); } @@ -374,9 +375,9 @@ LRESULT MainFrame::OnActivateApp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/ { BOOL bActivating = static_cast(wParam); - if (!m_activeView) return 0; + if (!m_activeTabView) return 0; - m_activeView->SetAppActiveStatus(bActivating ? true : false); + m_activeTabView->SetAppActiveStatus(bActivating ? true : false); TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; @@ -546,11 +547,11 @@ LRESULT MainFrame::OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& / { m_dwResizeWindowEdge = static_cast(wParam); - if (!m_activeView) + if (!m_activeTabView) return 0; - m_activeView->SetResizing(true); - + m_activeTabView->SetResizing(true); +#if 0 CPoint pointSize = m_activeView->GetCellSize(); RECT *rectNew = (RECT *)lParam; @@ -568,7 +569,7 @@ LRESULT MainFrame::OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& / if (rectWindow.right != rectNew->right) rectNew->right += (rectWindow.right - rectNew->right) - (rectWindow.right - rectNew->right) / pointSize.x * pointSize.x; - +#endif return 0; } @@ -661,12 +662,12 @@ LRESULT MainFrame::OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM } - if (m_activeView) + if (m_activeTabView) { CRect rectClient; GetClientRect(&rectClient); - m_activeView->MainframeMoving(); + m_activeTabView->MainframeMoving(); // we need to invalidate client rect here for proper background // repaint when using relative backgrounds InvalidateRect(&rectClient, FALSE); @@ -777,7 +778,7 @@ LRESULT MainFrame::OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lPar g_imageHandler->ReloadDesktopImages(); // can't use Invalidate because full repaint is in order - m_activeView->Repaint(true); + m_activeTabView->Repaint(true); } return 0; @@ -790,11 +791,6 @@ LRESULT MainFrame::OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lPar LRESULT MainFrame::OnConsoleResized(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /* bHandled */) { - // update rows/columns - SharedMemory& consoleParams = m_activeView->GetConsoleHandler().GetConsoleParams(); - m_dwRows = consoleParams->dwRows; - m_dwColumns = consoleParams->dwColumns; - AdjustWindowSize(false); UpdateStatusBar(); return 0; @@ -818,25 +814,27 @@ LRESULT MainFrame::OnConsoleClosed(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam LRESULT MainFrame::OnUpdateTitles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /* bHandled */) { - MutexLock viewMapLock(m_viewsMutex); - ConsoleViewMap::iterator itView = m_views.find(reinterpret_cast(wParam)); + MutexLock viewMapLock(m_tabsMutex); + TabViewMap::iterator itView = m_tabs.find(reinterpret_cast(wParam)); - if (itView == m_views.end()) return 0; + if (itView == m_tabs.end()) return 0; + shared_ptr tabView(itView->second); + shared_ptr consoleView = itView->second->GetActiveConsole(); + if (!consoleView) return 0; - shared_ptr consoleView(itView->second); WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; if (windowSettings.bUseConsoleTitle) { CString strTabTitle(consoleView->GetTitle()); - UpdateTabTitle(consoleView, strTabTitle); + UpdateTabTitle(*tabView, strTabTitle); if ((m_strCmdLineWindowTitle.GetLength() == 0) && (windowSettings.bUseTabTitles) && - (consoleView == m_activeView)) + (tabView == m_activeTabView)) { - m_strWindowTitle = consoleView->GetTitle(); + m_strWindowTitle = strTabTitle; SetWindowText(m_strWindowTitle); if (g_settingsHandler->GetAppearanceSettings().stylesSettings.bTrayIcon) SetTrayIcon(NIM_MODIFY); } @@ -855,7 +853,7 @@ LRESULT MainFrame::OnUpdateTitles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam* m_strWindowTitle = windowSettings.strTitle.c_str(); } - if (consoleView == m_activeView) + if (tabView == m_activeTabView) { if ((m_strCmdLineWindowTitle.GetLength() == 0) && (windowSettings.bUseTabTitles)) { @@ -870,7 +868,7 @@ LRESULT MainFrame::OnUpdateTitles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam* if (windowSettings.bShowCommandInTabs) strTabTitle += strCommandText; - UpdateTabTitle(consoleView, strTabTitle); + UpdateTabTitle(*tabView, strTabTitle); } return 0; @@ -989,13 +987,13 @@ LRESULT MainFrame::OnTabChanged(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) CTabViewTabItem* pTabItem1 = (pTabItems->iItem1 != 0xFFFFFFFF) ? m_TabCtrl.GetItem(pTabItems->iItem1) : NULL; CTabViewTabItem* pTabItem2 = m_TabCtrl.GetItem(pTabItems->iItem2); - MutexLock viewMapLock(m_viewsMutex); - ConsoleViewMap::iterator it; + MutexLock viewMapLock(m_tabsMutex); + TabViewMap::iterator it; if (pTabItem1) { - it = m_views.find(pTabItem1->GetTabView()); - if (it != m_views.end()) + it = m_tabs.find(pTabItem1->GetTabView()); + if (it != m_tabs.end()) { it->second->SetActive(false); } @@ -1003,29 +1001,32 @@ LRESULT MainFrame::OnTabChanged(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) if (pTabItem2) { - it = m_views.find(pTabItem2->GetTabView()); - if (it != m_views.end()) + it = m_tabs.find(pTabItem2->GetTabView()); + if (it != m_tabs.end()) { - UISetCheck(ID_VIEW_CONSOLE, it->second->GetConsoleWindowVisible() ? TRUE : FALSE); - m_activeView = it->second; + m_activeTabView = it->second; it->second->SetActive(true); if (appearanceSettings.windowSettings.bUseTabIcon) SetWindowIcons(); // clear the highlight in case it's on - HighlightTab(m_activeView->m_hWnd, false); + HighlightTab(m_activeTabView->m_hWnd, false); } else { - m_activeView = shared_ptr(); + m_activeTabView = shared_ptr(); } } if (appearanceSettings.stylesSettings.bTrayIcon) SetTrayIcon(NIM_MODIFY); - - if (appearanceSettings.windowSettings.bUseTabTitles && m_activeView) + + if (appearanceSettings.windowSettings.bUseTabTitles && m_activeTabView) { - SetWindowText(m_activeView->GetTitle()); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + SetWindowText(activeConsoleView->GetTitle()); + } } bHandled = FALSE; @@ -1203,11 +1204,14 @@ LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeView) return 0; - - m_activeView->Paste(); + if (!m_activeTabView) return 0; + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + activeConsoleView->Paste(); + } - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1217,11 +1221,14 @@ LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, LRESULT MainFrame::OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeView) return 0; - - m_activeView->Copy(); + if (!m_activeTabView) return 0; + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + activeConsoleView->Copy(); + } - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1231,11 +1238,14 @@ LRESULT MainFrame::OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeView) return 0; - - m_activeView->ClearSelection(); + if (!m_activeTabView) return 0; + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + activeConsoleView->ClearSelection(); + } - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1245,11 +1255,14 @@ LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeView) return 0; - - m_activeView->Paste(); + if (!m_activeTabView) return 0; + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + activeConsoleView->Paste(); + } - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1259,11 +1272,14 @@ LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt LRESULT MainFrame::OnEditStopScrolling(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeView) return 0; - - m_activeView->GetConsoleHandler().StopScrolling(); + if (!m_activeTabView) return 0; + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + activeConsoleView->GetConsoleHandler().StopScrolling(); + } - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1273,26 +1289,21 @@ LRESULT MainFrame::OnEditStopScrolling(WORD /*wNotifyCode*/, WORD /*wID*/, HWND LRESULT MainFrame::OnEditRenameTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeView) return 0; + if (!m_activeTabView) return 0; - DlgRenameTab dlg(m_activeView->GetTitle()); + DlgRenameTab dlg(m_activeTabView->GetTitle()); - if (dlg.DoModal() == IDOK) - { - - m_activeView->SetTitle(dlg.m_strTabName); - - WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; - CString strTabTitle(dlg.m_strTabName); - - if (windowSettings.bShowCommandInTabs) strTabTitle += m_activeView->GetConsoleCommand(); - - UpdateTabTitle(m_activeView, strTabTitle); + if (dlg.DoModal() == IDOK) + { + m_activeTabView->SetTitle(dlg.m_strTabName); - if (windowSettings.bUseTabTitles) SetWindowText(m_activeView->GetTitle()); - } + this->PostMessage( + UM_UPDATE_TITLES, + reinterpret_cast(m_activeTabView->m_hWnd), + 0); + } - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1302,7 +1313,7 @@ LRESULT MainFrame::OnEditRenameTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hW LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeView) return 0; + if (!m_activeTabView) return 0; DlgSettingsMain dlg; @@ -1334,10 +1345,10 @@ LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn BOOL bShowTabs = FALSE; - MutexLock viewMapLock(m_viewsMutex); + MutexLock viewMapLock(m_tabsMutex); if ( controlsSettings.bShowTabs && - (!controlsSettings.bHideSingleTab || (m_views.size() > 1)) + (!controlsSettings.bHideSingleTab || (m_tabs.size() > 1)) ) { bShowTabs = TRUE; @@ -1349,15 +1360,15 @@ LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn SetZOrder(g_settingsHandler->GetAppearanceSettings().positionSettings.zOrder); - for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) { it->second->InitializeScrollbars(); } - m_activeView->RecreateFont(); + ConsoleView::RecreateFont(); AdjustWindowSize(false); RecreateOffscreenBuffers(); - m_activeView->Repaint(true); + m_activeTabView->Repaint(true); } RegisterGlobalHotkeys(); @@ -1420,13 +1431,17 @@ LRESULT MainFrame::OnViewTabs(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnViewConsole(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (m_activeView) - { - m_activeView->SetConsoleWindowVisible(!m_activeView->GetConsoleWindowVisible()); - UISetCheck(ID_VIEW_CONSOLE, m_activeView->GetConsoleWindowVisible() ? TRUE : FALSE); - } + if (m_activeTabView) + { + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + activeConsoleView->SetConsoleWindowVisible(!activeConsoleView->GetConsoleWindowVisible()); + UISetCheck(ID_VIEW_CONSOLE, activeConsoleView->GetConsoleWindowVisible() ? TRUE : FALSE); + } + } - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1448,11 +1463,16 @@ LRESULT MainFrame::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnDumpBuffer(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeView) return 0; - - m_activeView->DumpBuffer(); + if (m_activeTabView) + { + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + activeConsoleView->DumpBuffer(); + } + } - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// @@ -1497,132 +1517,42 @@ void MainFrame::AdjustWindowRect(CRect& rect) ////////////////////////////////////////////////////////////////////////////// -bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir /*= wstring(L"")*/, const wstring& strStartupCmd /*= wstring(L"")*/, const wstring& strDbgCmdLine /*= wstring(L"")*/) +bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir /*= wstring(L"")*/, const wstring& strStartupCmd /*= wstring(L"")*/) { if (dwTabIndex >= g_settingsHandler->GetTabSettings().tabDataVector.size()) return false; - DWORD dwRows = g_settingsHandler->GetConsoleSettings().dwRows; - DWORD dwColumns = g_settingsHandler->GetConsoleSettings().dwColumns; - - MutexLock viewMapLock(m_viewsMutex); - if (m_views.size() > 0) - { - SharedMemory& consoleParams = m_views.begin()->second->GetConsoleHandler().GetConsoleParams(); - dwRows = consoleParams->dwRows; - dwColumns = consoleParams->dwColumns; - } - else - { - // initialize member variables for the first view - m_dwRows = dwRows; - m_dwColumns = dwColumns; - } + MutexLock tabMapLock(m_tabsMutex); shared_ptr tabData = g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]; - shared_ptr consoleView(new ConsoleView(*this, dwTabIndex, strStartupDir, strStartupCmd, strDbgCmdLine, dwRows, dwColumns)); - UserCredentials userCredentials; - - if (tabData->bRunAsUser) - { -#ifdef _USE_AERO - // Display a dialog box to request credentials. - CREDUI_INFOW ui; - ui.cbSize = sizeof(ui); - ui.hwndParent = GetConsoleWindow(); - ui.pszMessageText = tabData->strShell.c_str(); - ui.pszCaptionText = L"Enter username and password"; - ui.hbmBanner = NULL; - - // we need a target - WCHAR szModuleFileName[_MAX_PATH] = L""; - ::GetModuleFileName(NULL, szModuleFileName, ARRAYSIZE(szModuleFileName)); - - WCHAR szUser [CREDUI_MAX_USERNAME_LENGTH + 1] = L""; - WCHAR szPassword[CREDUI_MAX_PASSWORD_LENGTH + 1] = L""; - wcscpy_s(szUser, ARRAYSIZE(szUser), tabData->strUser.c_str()); - - DWORD rc = ::CredUIPromptForCredentials( - &ui, //__in_opt PCREDUI_INFO pUiInfo, - szModuleFileName, //__in PCTSTR pszTargetName, - NULL, //__in PCtxtHandle Reserved, - 0, //__in_opt DWORD dwAuthError, - szUser, //__inout PCTSTR pszUserName, - ARRAYSIZE(szUser), //__in ULONG ulUserNameMaxChars, - szPassword, //__inout PCTSTR pszPassword, - ARRAYSIZE(szPassword), //__in ULONG ulPasswordMaxChars, - NULL, //__inout PBOOL pfSave, - CREDUI_FLAGS_EXCLUDE_CERTIFICATES | //__in DWORD dwFlags - CREDUI_FLAGS_ALWAYS_SHOW_UI | - CREDUI_FLAGS_GENERIC_CREDENTIALS | - CREDUI_FLAGS_DO_NOT_PERSIST - ); - - if( rc != NO_ERROR ) - return false; - - userCredentials.user = szUser; - userCredentials.password = szPassword; -#else - DlgCredentials dlg(tabData->strUser.c_str()); - - if (dlg.DoModal() != IDOK) return false; - - userCredentials.user = dlg.GetUser(); - userCredentials.password= dlg.GetPassword(); -#endif - } + shared_ptr tabView(new TabView(*this, tabData)); - HWND hwndConsoleView = consoleView->Create( + HWND hwndTabView = tabView->Create( m_hWnd, rcDefault, NULL, - WS_CHILD | WS_VISIBLE,// | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, - 0, - 0U, - reinterpret_cast(&userCredentials)); + WS_CHILD | WS_VISIBLE); - if (hwndConsoleView == NULL) + if (hwndTabView == NULL) { - CString strMessage(consoleView->GetExceptionMessage()); - - if (strMessage.GetLength() == 0) - { - // copied from ConsoleView::OnCreate - wstring strShell; - if (strDbgCmdLine.length() > 0) - { - strShell = strDbgCmdLine; - } - else if (tabData->strShell.length() > 0) - { - strShell = tabData->strShell; - } - // end of copy from ConsoleView::OnCreate - - strMessage.Format(IDS_TAB_CREATE_FAILED, g_settingsHandler->GetTabSettings().tabDataVector[dwTabIndex]->strTitle.c_str(), strShell.c_str()); - } - - ::MessageBox(m_hWnd, strMessage, L"Error", MB_OK|MB_ICONERROR); - return false; } - m_views.insert(ConsoleViewMap::value_type(hwndConsoleView, consoleView)); + m_tabs.insert(TabViewMap::value_type(hwndTabView, tabView)); CString strTabTitle; - consoleView->GetWindowText(strTabTitle); + tabView->GetWindowText(strTabTitle); - AddTabWithIcon(*consoleView, strTabTitle, consoleView->GetIcon(false)); - DisplayTab(hwndConsoleView, FALSE); + AddTabWithIcon(hwndTabView, strTabTitle, tabView->GetIcon(false)); + DisplayTab(hwndTabView, FALSE); ::SetForegroundWindow(m_hWnd); - if (m_views.size() > 1) + if (m_tabs.size() > 1) { UIEnable(ID_FILE_CLOSE_TAB, TRUE); } if ( g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowTabs && - ((m_views.size() > 1) || (!g_settingsHandler->GetAppearanceSettings().controlsSettings.bHideSingleTab)) + ((m_tabs.size() > 1) || (!g_settingsHandler->GetAppearanceSettings().controlsSettings.bHideSingleTab)) ) { ShowTabs(TRUE); @@ -1638,10 +1568,10 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir void MainFrame::CloseTab(CTabViewTabItem* pTabItem) { - MutexLock viewMapLock(m_viewsMutex); - if (!pTabItem) return; - if (m_views.size() <= 1) return; - CloseTab(pTabItem->GetTabView()); + MutexLock viewMapLock(m_tabsMutex); + if (!pTabItem) return; + if (m_tabs.size() <= 1) return; + CloseTab(pTabItem->GetTabView()); } ////////////////////////////////////////////////////////////////////////////// @@ -1649,29 +1579,29 @@ void MainFrame::CloseTab(CTabViewTabItem* pTabItem) ////////////////////////////////////////////////////////////////////////////// -void MainFrame::CloseTab(HWND hwndConsoleView) +void MainFrame::CloseTab(HWND hwndTabView) { - MutexLock viewMapLock(m_viewsMutex); - ConsoleViewMap::iterator it = m_views.find(hwndConsoleView); - if (it == m_views.end()) return; + MutexLock viewMapLock(m_tabsMutex); + TabViewMap::iterator it = m_tabs.find(hwndTabView); + if (it == m_tabs.end()) return; - RemoveTab(hwndConsoleView); - if (m_activeView == it->second) m_activeView.reset(); - it->second->DestroyWindow(); - m_views.erase(it); + RemoveTab(hwndTabView); + if (m_activeTabView == it->second) m_activeTabView.reset(); + it->second->DestroyWindow(); + m_tabs.erase(it); - if (m_views.size() == 1) - { - UIEnable(ID_FILE_CLOSE_TAB, FALSE); - } - if ((m_views.size() == 1) && - m_bTabsVisible && - (g_settingsHandler->GetAppearanceSettings().controlsSettings.bHideSingleTab)) - { - ShowTabs(FALSE); - } + if (m_tabs.size() == 1) + { + UIEnable(ID_FILE_CLOSE_TAB, FALSE); + } + if ((m_tabs.size() == 1) && + m_bTabsVisible && + (g_settingsHandler->GetAppearanceSettings().controlsSettings.bHideSingleTab)) + { + ShowTabs(FALSE); + } - if (m_views.size() == 0) PostMessage(WM_CLOSE); + if (m_tabs.size() == 0) PostMessage(WM_CLOSE); } ////////////////////////////////////////////////////////////////////////////// @@ -1679,10 +1609,10 @@ void MainFrame::CloseTab(HWND hwndConsoleView) ////////////////////////////////////////////////////////////////////////////// -void MainFrame::UpdateTabTitle(const shared_ptr& consoleView, CString& strTabTitle) +void MainFrame::UpdateTabTitle(HWND hwndTabView, CString& strTabTitle) { // we always set the tool tip text to the complete, untrimmed title - UpdateTabToolTip(*consoleView, strTabTitle); + UpdateTabToolTip(hwndTabView, strTabTitle); WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; @@ -1698,7 +1628,7 @@ void MainFrame::UpdateTabTitle(const shared_ptr& consoleView, CStri strTabTitle = strTabTitle.Left(windowSettings.dwTrimTabTitles - windowSettings.dwTrimTabTitlesRight) + CString(L"...") + strTabTitle.Right(windowSettings.dwTrimTabTitlesRight); } - UpdateTabText(*consoleView, strTabTitle); + UpdateTabText(hwndTabView, strTabTitle); } ////////////////////////////////////////////////////////////////////////////// @@ -1770,14 +1700,29 @@ void MainFrame::UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu) void MainFrame::UpdateStatusBar() { - CString strRowsCols; - if( m_iSelectionSize ) - strRowsCols.Format(_T("[%i]"), m_iSelectionSize); - else - strRowsCols.Format(IDPANE_ROWS_COLUMNS, m_dwRows, m_dwColumns); - UISetText(1, strRowsCols); + CString strRowsCols; + if( m_iSelectionSize ) + strRowsCols.Format(_T("[%i]"), m_iSelectionSize); + else + { + DWORD dwRows = 0, dwColumns = 0; + + if (m_activeTabView) + { + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + if( activeConsoleView ) + { + SharedMemory& consoleParams = activeConsoleView->GetConsoleHandler().GetConsoleParams(); + dwRows = consoleParams->dwRows; + dwColumns = consoleParams->dwColumns; + } + } - UIUpdateStatusBar(); + strRowsCols.Format(IDPANE_ROWS_COLUMNS, dwRows, dwColumns); + } + UISetText(1, strRowsCols); + + UIUpdateStatusBar(); } void MainFrame::SetSelectionSize(int iSelectionSize) @@ -1927,10 +1872,10 @@ void MainFrame::SetWindowIcons() if (!m_icon.IsNull()) m_icon.DestroyIcon(); if (!m_smallIcon.IsNull()) m_smallIcon.DestroyIcon(); - if (windowSettings.bUseTabIcon && m_activeView) + if (windowSettings.bUseTabIcon && m_activeTabView) { - m_icon.Attach(m_activeView->GetIcon(true).DuplicateIcon()); - m_smallIcon.Attach(m_activeView->GetIcon(false).DuplicateIcon()); + m_icon.Attach(m_activeTabView->GetIcon(true).DuplicateIcon()); + m_smallIcon.Attach(m_activeTabView->GetIcon(false).DuplicateIcon()); } else { @@ -2071,7 +2016,7 @@ void MainFrame::ResizeWindow() SendMessage(WM_NULL, 0, 0); m_dwResizeWindowEdge = WMSZ_BOTTOM; - if (m_activeView) m_activeView->SetResizing(false); + if (m_activeTabView) m_activeTabView->SetResizing(false); } ////////////////////////////////////////////////////////////////////////////// @@ -2083,56 +2028,52 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole) { CRect clientRect(0, 0, 0, 0); - bool bMaximized = false; if( this->IsZoomed() ) { - bMaximized = true; bResizeConsole = true; } if (bResizeConsole) { // adjust the active view - if (!m_activeView) return; + if (!m_activeTabView) return; - // if we're being maximized, AdjustRectAndResize will use client rect supplied - m_activeView->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge, bMaximized); + m_activeTabView->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge); // for other views, first set view size and then resize their Windows consoles - MutexLock viewMapLock(m_viewsMutex); + MutexLock viewMapLock(m_tabsMutex); - for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) { - if (m_activeView == it->second) continue; + if (m_activeTabView == it->second) continue; it->second->SetWindowPos( - 0, - 0, - 0, - clientRect.Width(), - clientRect.Height(), + 0, + 0, + 0, + clientRect.Width(), + clientRect.Height(), SWP_NOMOVE|SWP_NOZORDER|SWP_NOSENDCHANGING); - // if we're being maximized, AdjustRectAndResize will use client rect supplied - it->second->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge, bMaximized); + it->second->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge); } } else { - if (!m_activeView) return; + if (!m_activeTabView) return; - m_activeView->GetRect(clientRect); + m_activeTabView->GetRect(clientRect); } AdjustWindowRect(clientRect); // TRACE(L"AdjustWindowSize: %ix%i\n", clientRect.Width(), clientRect.Height()); SetWindowPos( - 0, - 0, - 0, - clientRect.Width(), - clientRect.Height() + 4, + 0, + 0, + 0, + clientRect.Width(), + clientRect.Height() + 4, SWP_NOMOVE|SWP_NOZORDER|SWP_NOSENDCHANGING); // update window width and height @@ -2148,9 +2089,9 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole) void MainFrame::RecreateOffscreenBuffers() { - MutexLock viewMapLock(m_viewsMutex); + MutexLock viewMapLock(m_tabsMutex); - for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) { it->second->RecreateOffscreenBuffers(); } @@ -2189,7 +2130,7 @@ void MainFrame::SetMargins(void) m_Margins.cyBottomHeight = 0; } SetTransparency(); - } +} void MainFrame::SetTransparency() { diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 71cb2384..b2b58c67 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -16,10 +16,8 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -class ConsoleView; - - -typedef map > ConsoleViewMap; +class TabView; +typedef map > TabViewMap; ////////////////////////////////////////////////////////////////////////////// @@ -44,8 +42,7 @@ class MainFrame const vector& startupTabs, const vector& startupDirs, const vector& startupCmds, - int nMultiStartSleep, - const wstring& strDbgCmdLine + int nMultiStartSleep ); virtual BOOL PreTranslateMessage(MSG* pMsg); @@ -199,11 +196,11 @@ class MainFrame private: - bool CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir = wstring(L""), const wstring& strStartupCmd = wstring(L""), const wstring& strDbgCmdLine = wstring(L"")); + bool CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir = wstring(L""), const wstring& strStartupCmd = wstring(L"")); void CloseTab(CTabViewTabItem* pTabItem); - void CloseTab(HWND hwndConsoleView); + void CloseTab(HWND hwndTabView); - void UpdateTabTitle(const shared_ptr& consoleView, CString& strTabTitle); + void UpdateTabTitle(HWND hwndTabView, CString& strTabTitle); void UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu); void UpdateStatusBar(); void SetWindowStyles(); @@ -235,9 +232,8 @@ class MainFrame const vector& m_startupDirs; const vector& m_startupCmds; int m_nMultiStartSleep; - wstring m_strDbgCmdLine; - shared_ptr m_activeView; + shared_ptr m_activeTabView; BOOL m_bMenuVisible; BOOL m_bToolbarVisible; @@ -248,8 +244,8 @@ class MainFrame ZOrder m_zOrder; CPoint m_mousedragOffset; - ConsoleViewMap m_views; - Mutex m_viewsMutex; + TabViewMap m_tabs; + Mutex m_tabsMutex; CMenu m_tabsMenu; @@ -259,8 +255,6 @@ class MainFrame CString m_strCmdLineWindowTitle; CString m_strWindowTitle; - DWORD m_dwRows; - DWORD m_dwColumns; int m_iSelectionSize; DWORD m_dwWindowWidth; diff --git a/Console/TabView.cpp b/Console/TabView.cpp new file mode 100644 index 00000000..936e9e6d --- /dev/null +++ b/Console/TabView.cpp @@ -0,0 +1,298 @@ +#include "stdafx.h" + +#include "Console.h" +#include "TabView.h" +#include "DlgCredentials.h" + +int CMultiSplitPane::splitBarWidth = 0; +int CMultiSplitPane::splitBarHeight = 0; + + +////////////////////////////////////////////////////////////////////////////// + +TabView::TabView(MainFrame& mainFrame, shared_ptr tabData) +:m_mainFrame(mainFrame) +,m_viewsMutex(NULL, FALSE, NULL) +,m_tabData(tabData) +,m_strTitle(tabData->strTitle.c_str()) +,m_bigIcon() +,m_smallIcon() +{ +} + +TabView::~TabView() +{ +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +BOOL TabView::PreTranslateMessage(MSG* pMsg) +{ + shared_ptr consoleView = this->GetActiveConsole(); + if( consoleView ) + return consoleView->PreTranslateMessage(pMsg); + return FALSE; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT TabView::OnCreate (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled) +{ + // load icon + m_bigIcon.Attach(Helpers::LoadTabIcon(true, m_tabData->bUseDefaultIcon, m_tabData->strIcon, m_tabData->strShell)); + m_smallIcon.Attach(Helpers::LoadTabIcon(false, m_tabData->bUseDefaultIcon, m_tabData->strIcon, m_tabData->strShell)); + + LRESULT result = -1; + + ATLTRACE(_T("TabView::OnCreate\n")); + MutexLock viewMapLock(m_viewsMutex); + HWND hwndConsoleView = CreateNewConsole(); + if( hwndConsoleView ) + { + result = multisplitClass::OnCreate(uMsg, wParam, lParam, bHandled); + TRACE(L"multisplitClass::OnCreate returns %p\n", result); + if( result == 0 ) + { + multisplitClass::tree.window = hwndConsoleView; + } + } + + bHandled = TRUE; + ATLTRACE(_T("TabView::OnCreate done\n")); + return result; // windows sets focus to first control +} + +LRESULT TabView::OnEraseBackground (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/) +{ + // handled, no background painting needed + return 1; +} + +LRESULT TabView::OnSize (UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL & bHandled) +{ + if (wParam != SIZE_MINIMIZED) + RectSet (); // to ClientRect + + bHandled = FALSE; + return 1; +} + +HWND TabView::CreateNewConsole(void) +{ + DWORD dwRows = g_settingsHandler->GetConsoleSettings().dwRows; + DWORD dwColumns = g_settingsHandler->GetConsoleSettings().dwColumns; + + MutexLock viewMapLock(m_viewsMutex); +#if 0 + if (m_views.size() > 0) + { + SharedMemory& consoleParams = m_views.begin()->second->GetConsoleHandler().GetConsoleParams(); + dwRows = consoleParams->dwRows; + dwColumns = consoleParams->dwColumns; + } + else + { + // initialize member variables for the first view + m_dwRows = dwRows; + m_dwColumns = dwColumns; + } +#endif + shared_ptr consoleView(new ConsoleView(m_mainFrame, m_hWnd, m_tabData, m_strTitle, dwRows, dwColumns)); + UserCredentials userCredentials; + + if (m_tabData->bRunAsUser) + { +#ifdef _USE_AERO + // Display a dialog box to request credentials. + CREDUI_INFOW ui; + ui.cbSize = sizeof(ui); + ui.hwndParent = GetConsoleWindow(); + ui.pszMessageText = m_tabData->strShell.c_str(); + ui.pszCaptionText = L"Enter username and password"; + ui.hbmBanner = NULL; + + // we need a target + WCHAR szModuleFileName[_MAX_PATH] = L""; + ::GetModuleFileName(NULL, szModuleFileName, ARRAYSIZE(szModuleFileName)); + + WCHAR szUser [CREDUI_MAX_USERNAME_LENGTH + 1] = L""; + WCHAR szPassword[CREDUI_MAX_PASSWORD_LENGTH + 1] = L""; + wcscpy_s(szUser, ARRAYSIZE(szUser), m_tabData->strUser.c_str()); + + DWORD rc = ::CredUIPromptForCredentials( + &ui, //__in_opt PCREDUI_INFO pUiInfo, + szModuleFileName, //__in PCTSTR pszTargetName, + NULL, //__in PCtxtHandle Reserved, + 0, //__in_opt DWORD dwAuthError, + szUser, //__inout PCTSTR pszUserName, + ARRAYSIZE(szUser), //__in ULONG ulUserNameMaxChars, + szPassword, //__inout PCTSTR pszPassword, + ARRAYSIZE(szPassword), //__in ULONG ulPasswordMaxChars, + NULL, //__inout PBOOL pfSave, + CREDUI_FLAGS_EXCLUDE_CERTIFICATES | //__in DWORD dwFlags + CREDUI_FLAGS_ALWAYS_SHOW_UI | + CREDUI_FLAGS_GENERIC_CREDENTIALS | + CREDUI_FLAGS_DO_NOT_PERSIST + ); + + if( rc != NO_ERROR ) + return 0; + + userCredentials.user = szUser; + userCredentials.password = szPassword; +#else + DlgCredentials dlg(m_tabData->strUser.c_str()); + + if (dlg.DoModal() != IDOK) return 0; + + userCredentials.user = dlg.GetUser(); + userCredentials.password= dlg.GetPassword(); +#endif + } + + HWND hwndConsoleView = consoleView->Create( + m_hWnd, + rcDefault, + NULL, + WS_CHILD | WS_VISIBLE,// | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + 0, + 0U, + reinterpret_cast(&userCredentials)); + + if (hwndConsoleView == NULL) + { + CString strMessage(consoleView->GetExceptionMessage()); + + if (strMessage.GetLength() == 0) + { + strMessage.Format(IDS_TAB_CREATE_FAILED, m_tabData->strTitle.c_str(), m_tabData->strShell.c_str()); + } + + ::MessageBox(m_hWnd, strMessage, L"Error", MB_OK|MB_ICONERROR); + + return 0; + } + + m_views.insert(ConsoleViewMap::value_type(hwndConsoleView, consoleView)); + + return hwndConsoleView; +} + +shared_ptr TabView::GetActiveConsole() +{ + shared_ptr result; + if( this->defaultFocusPane && defaultFocusPane->window ) + { + MutexLock viewMapLock(m_viewsMutex); + ConsoleViewMap::iterator iter = m_views.find(defaultFocusPane->window); + if( iter != m_views.end() ) + result = iter->second; + else + TRACE(L"defaultFocusPane->window = %p not found !!!\n", defaultFocusPane->window); + } + else + { + TRACE(L"TabView::GetActiveConsole this->defaultFocusPane = %p\n", this->defaultFocusPane); + } + TRACE(L"TabView::GetActiveConsole returns %p\n", result.get()); + return result; +} + +void TabView::GetRect(CRect& clientRect) +{ + clientRect = this->visibleRect; +} + +void TabView::InitializeScrollbars() +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->InitializeScrollbars(); + } +} + +void TabView::Repaint(bool bFullRepaint) +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->Repaint(bFullRepaint); + } +} + +void TabView::SetResizing(bool bResizing) +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetResizing(bResizing); + } +} + +void TabView::MainframeMoving() +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->MainframeMoving(); + } +} + +void TabView::RecreateOffscreenBuffers() +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->RecreateOffscreenBuffers(); + } +} + +void TabView::SetTitle(const CString& strTitle) +{ + m_strTitle = strTitle; + + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetTitle(strTitle); + } +} + +void TabView::SetActive(bool bActive) +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetActive(bActive); + } +} + +void TabView::SetAppActiveStatus(bool bAppActive) +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetAppActiveStatus(bAppActive); + } +} + +void TabView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge) +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->AdjustRectAndResize(clientRect, dwResizeWindowEdge); + } +} \ No newline at end of file diff --git a/Console/TabView.h b/Console/TabView.h new file mode 100644 index 00000000..2086d007 --- /dev/null +++ b/Console/TabView.h @@ -0,0 +1,71 @@ +#pragma once + +#include "ConsoleView.h" + +typedef map > ConsoleViewMap; + +class TabView + : public CWindowImpl + , public CMultiSplitImpl +{ +public: + DECLARE_WND_CLASS_EX(L"Console_2_TabView", CS_DBLCLKS, COLOR_WINDOW) + + TabView(MainFrame& mainFrame, shared_ptr tabData); + ~TabView(); + + BOOL PreTranslateMessage(MSG* pMsg); + + typedef CMultiSplitImpl< TabView > multisplitClass; + BEGIN_MSG_MAP(TabView) + MESSAGE_HANDLER (WM_CREATE, OnCreate) + MESSAGE_HANDLER (WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER (WM_SIZE, OnSize) + CHAIN_MSG_MAP (multisplitClass) + FORWARD_NOTIFICATIONS () + END_MSG_MAP() + + // Handler prototypes (uncomment arguments if needed): + // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) + // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) + // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) + + LRESULT OnCreate (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled); + LRESULT OnEraseBackground (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/); + LRESULT OnSize (UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL & bHandled); + + shared_ptr GetActiveConsole(); + shared_ptr GetTabData() { return m_tabData; } + + void SetTitle(const CString& strTitle); + const CString& GetTitle() const { return m_strTitle; } + CIcon& GetIcon(bool bBigIcon = true) { return bBigIcon ? m_bigIcon : m_smallIcon; } + void SetActive(bool bActive); + void SetAppActiveStatus(bool bAppActive); + void SetResizing(bool bResizing); + void MainframeMoving(); + void Repaint(bool bFullRepaint); + void InitializeScrollbars(); + void RecreateOffscreenBuffers(); + void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge); + void GetRect(CRect& clientRect); + +private: + HWND CreateNewConsole(void); + +private: + MainFrame& m_mainFrame; + ConsoleViewMap m_views; + Mutex m_viewsMutex; + shared_ptr m_tabData; + CString m_strTitle; + CIcon m_bigIcon; + CIcon m_smallIcon; + + + // static members +private: + +}; + +////////////////////////////////////////////////////////////////////////////// diff --git a/Console/stdafx.h b/Console/stdafx.h index d3b175b8..b814ca0b 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -78,6 +78,7 @@ extern CAppModule _Module; #include "TabbedFrame.h" #pragma warning(pop) +#include "multisplit.h" #include #include diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index a5ecccb6..e695ea3b 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -570,12 +570,10 @@ class ClipboardDataRtf : public ClipboardData strRtf += "{\\colortbl\n"; for(int i = 0; i < 16; i ++) { - int red = (pconsoleCopy->consoleColors[i] >> 16) & 0xff; - int green = (pconsoleCopy->consoleColors[i] >> 8 ) & 0xff; - int blue = (pconsoleCopy->consoleColors[i] ) & 0xff; char szColor[64]; - _snprintf( + _snprintf_s( szColor, sizeof(szColor), + _TRUNCATE, "\\red%lu\\green%lu\\blue%lu;\n", GetRValue(pconsoleCopy->consoleColors[i]), GetGValue(pconsoleCopy->consoleColors[i]), @@ -585,8 +583,9 @@ class ClipboardDataRtf : public ClipboardData strRtf += "}"; char szFont[64]; - _snprintf( + _snprintf_s( szFont, sizeof(szFont), + _TRUNCATE, "\\f0\\fs%lu%s%s\n", pconsoleCopy->dwSize, pconsoleCopy->bBold ? "\\b" : "", @@ -617,16 +616,18 @@ class ClipboardDataRtf : public ClipboardData } if( wLastCharBackgroundAttributes != wCharBackgroundAttributes ) { - _snprintf( + _snprintf_s( szDummy, sizeof(szDummy), + _TRUNCATE, "\\highlight%hu ", wCharBackgroundAttributes); strRow += szDummy; } if( wLastCharForegroundAttributes != wCharForegroundAttributes ) { - _snprintf( + _snprintf_s( szDummy, sizeof(szDummy), + _TRUNCATE, "\\cf%hu ", wCharForegroundAttributes); strRow += szDummy; @@ -641,7 +642,7 @@ class ClipboardDataRtf : public ClipboardData else if( wc <= 0x7f ) strRow += p->Char.AsciiChar; else { - _snprintf(szDummy, sizeof(szDummy), "\\u%d?", wc); + _snprintf_s(szDummy, sizeof(szDummy), _TRUNCATE, "\\u%d?", wc); strRow += szDummy; } sizeRowLen ++; diff --git a/wtl/wtl/include/multisplit.h b/wtl/wtl/include/multisplit.h new file mode 100644 index 00000000..ab34db93 --- /dev/null +++ b/wtl/wtl/include/multisplit.h @@ -0,0 +1,960 @@ +/**************************************************************************** + * * + * MultiSplit.h: Scrolling multi-panel splitter for use with WTL * + * * + * Written by Ted Szoczei (ted.szoczei@nimajin.com), * + * Nimajin Software Consulting * + * for Microtronix Systems Ltd. * + * Copyright (c) 2003-2004 Ted Szoczei. * + * * + * Portions adapted from Windows Template Library - WTL version 7.0, * + * atlsplit.h * + * Copyright (C) 1997-2002 Microsoft Corporation, All rights reserved. * + * * + * Permission to copy, use, sell and distribute this file is granted * + * provided this copyright notice appears in all copies. * + * Permission to modify the code herein and to distribute modified code is * + * granted provided this copyright notice appears in all copies, and a * + * notice that the code was modified is included with the copyright notice. * + * * + * This software and information is provided "as is" without express or im- * + * plied warranty, and with no claim as to its suitability for any purpose. * + * * + * Find the latest version at http://www.nimajin.com * + * * + **************************************************************************** + * REVISIONS * + * --------- * + * DATE VER CHANGES /BY * + * ---------- ----- ----------- * + * 08-04-25: Added PanesCount property and Contains method. * + * Revised Insert so index >= PanesCount will Add, not assert./tsz* + * 04-12-13: Added mouse wheel scrolling support. * + * Added SetFocus to MouseActivate so mouse wheel works whenever * + * window active. /tsz * + * 03-05-16: Initial release. /tsz * + * * + **************************************************************************** + * NOTES * + * ----- * + * Limited mode behaviour: * + * For one or two panes, multi-splitter acts the same as a regular two-pane* + * splitter. * + * Panes are limited in size to fill visible area. * + * The last pane resizes to fit the area left by other panes. * + * Resizing a pane affects only the pane on the other side of the splitter * + * bar. * + * Specifying -1 for a pane size resizes all panes to fit evenly within the* + * window. * + * * + * Scroll mode behaviour: * + * Panes always start with the size specified, the virtual display area * + * grows to fit them. * + * Panes can be any size. * + * Resizing a pane moves all following panes. * + * There is always an empty square pane at the end for the last pane to * + * resize into. * + * Specifying -1 for a pane size gives it the average size of all existing * + * panes, or evenly divides them into visible space if all are -1. * + * * + * All extended styles can be switched at any time by calling * + * SetExtendedStyle. * + * Panes can be added to the end or inserted between existing panes. * + * Panes can be removed or replaced. Panes are indexed starting with 0. * + * * + * No right/bottom alignment support. * + * * + ****************************************************************************/ + + +#ifndef __ATLMULTISPLIT_H__ +#define __ATLMULTISPLIT_H__ + +#pragma once + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLAPP_H__ + #error multisplit.h requires atlapp.h to be included first +#endif + +#ifndef __ATLWIN_H__ + #error multisplit.h requires atlwin.h to be included first +#endif + + +#include // CRect +#include // CAtlArray +#include // CAtlArray + + +///////////////////////////////////////////////////////////////////////////// +// Classes in this file +// +// CMultiSplitImpl +// CMultiSplitWindowImpl +// CMultiSplitWindow + + +namespace WTL +{ + +///////////////////////////////////////////////////////////////////////////// +// CMultiSplitImpl - Provides multi-pane splitter support to any window + + class CMultiSplitPane + { + public: + typedef enum + { + NONE, + HORIZONTAL, + VERTICAL + } + SPLITTYPE; + + typedef enum + { + ROOT, + TOP, + BOTTOM, + LEFT, + RIGHT + } + WHERE; + + HWND window; + int x; + int y; + int width; + int height; + SPLITTYPE splitType; // split type + int splitRatio; // ratio in percent of pane0 + CMultiSplitPane* pane0; // if splitted left or top pane + CMultiSplitPane* pane1; // if splitted right or bottom pane + CMultiSplitPane* parent; // pane containing this pane + + CMultiSplitPane(void) + : window (0) + , x (0) + , y (0) + , width (0) + , height (0) + , splitType (NONE) + , splitRatio(100) + , pane0 (0) + , pane1 (0) + , parent (0) + { + } + + CMultiSplitPane(HWND window, int x, int y, int width, int height, CMultiSplitPane* parent) + : window (window) + , x (x) + , y (y) + , width (width) + , height (height) + , splitType (NONE) + , splitRatio(100) + , pane0 (0) + , pane1 (0) + , parent (parent) + { + } + + ~CMultiSplitPane(void) + { + delete this->pane0; + delete this->pane1; + } + + WHERE whereAmI(void) + { + if( this->parent == 0 ) + return ROOT; + + bool isPane0 = this->parent->pane0 == this; + if( this->parent->splitType == VERTICAL ) + return isPane0 ? TOP : BOTTOM; + else + return isPane0 ? LEFT : RIGHT; + } + + CMultiSplitPane* split(HWND windowPane1, SPLITTYPE splitType) + { + if( this->isSplitBar() ) + return 0; + + int pane0Width, pane0Height, pane1Width, pane1Height, pane1X, pane1Y; + + this->splitType = splitType; + this->splitRatio = 50; + if( this->splitType == HORIZONTAL ) + { + pane1Width = pane0Width = this->width; + pane0Height = (this->height - CMultiSplitPane::splitBarHeight) / 2; + pane1Height = this->height - CMultiSplitPane::splitBarHeight - pane0Height; + pane1X = this->x; + pane1Y = this->y + pane0Height + CMultiSplitPane::splitBarHeight; + } + else + { + pane0Width = (this->width - CMultiSplitPane::splitBarWidth) / 2; + pane1Width = this->width - CMultiSplitPane::splitBarWidth - pane0Width; + pane1Height = pane0Height = this->height; + pane1X = this->x + pane0Width + CMultiSplitPane::splitBarWidth; + pane1Y = this->y; + } + + if( pane0Width <= 0 || pane1Width <= 0 || pane0Height <= 0 || pane1Height <= 0 ) + // too small + return 0; + + this->pane0 = new CMultiSplitPane( + this->window, + this->x, this->y, + pane0Width, pane0Height, + this); + this->pane1 = new CMultiSplitPane( + windowPane1, + pane1X, pane1Y, + pane1Width, pane1Height, + this); + + this->window = 0; + + // resize two children + this->pane0->resize(this->pane0->width, this->pane0->height); + this->pane1->updateLayout(); + + return this->pane1; + } + + void remove(void) + { + if( this->isSplitBar() ) + return; + + if( parent ) + { + CMultiSplitPane* survivor = + this->window == this->parent->pane0->window? + this->parent->pane1: + this->parent->pane0; + + CMultiSplitPane* target = + this->window == this->parent->pane0->window? + this->parent->pane0: + this->parent->pane1; + + ::SetWindowPos( + target->window, + 0, + 0, + 0, + 0, + 0, + SWP_HIDEWINDOW); + + // parent = survivor + this->parent->window = survivor->window; + this->parent->splitType = survivor->splitType; + this->parent->splitRatio = survivor->splitRatio; + this->parent->pane0 = survivor->pane0; + this->parent->pane1 = survivor->pane1; + this->parent->splitType = NONE; + + // resize parent + this->parent->resize(this->parent->width, this->parent->height); + + // delete the two children of the parent + delete target; + survivor->pane0 = 0; + survivor->pane1 = 0; + delete survivor; + } + } + + void resize(int width, int height) + { + this->width = width; + this->height = height; + if( this->pane0 ) + { + int pane0Width, pane0Height, pane1Width, pane1Height, pane1X, pane1Y; + + if( splitType == HORIZONTAL ) + { + pane1Width = pane0Width = this->width; + pane0Height = ::MulDiv(this->height - CMultiSplitPane::splitBarHeight, this->splitRatio, 100); + pane1Height = this->height - CMultiSplitPane::splitBarHeight - pane0Height; + pane1X = this->x; + pane1Y = this->y + pane0Height + CMultiSplitPane::splitBarHeight; + } + else + { + pane0Width = ::MulDiv(this->width - CMultiSplitPane::splitBarWidth, this->splitRatio, 100); + pane1Width = this->width - CMultiSplitPane::splitBarWidth - pane0Width; + pane1Height = pane0Height = this->height; + pane1X = this->x + pane0Width + CMultiSplitPane::splitBarWidth; + pane1Y = this->y; + } + + this->pane0->x = this->x; + this->pane0->y = this->y; + this->pane0->resize(pane0Width, pane0Height); + this->pane1->x = pane1X; + this->pane1->y = pane1Y; + this->pane1->resize(pane1Width, pane1Height); + } + else + { + // resize pane view + this->updateLayout(); + } + } + + void updateLayout(void) + { + ::SetWindowPos( + this->window, + 0, + this->x, + this->y, + this->width, + this->height, + SWP_NOZORDER | SWP_NOACTIVATE); + + ATLTRACE(_T("CMultiSplitPane::updateLayout: %d %d (%d %d)\n"), + this->x, this->y, + this->width, this->height); + } + + int getSplitBarDelta(POINT point) + { + if( this->pane0 == NULL ) + return 0; + + if( splitType == HORIZONTAL ) + { + return point.y - (this->pane0->y + this->pane0->height); + } + else + { + return point.x - (this->pane0->x + this->pane0->width); + } + } + + void getSplitBarRect(RECT& rect, int delta) + { + if( this->pane0 ) + { + if( this->splitType == HORIZONTAL ) + { + rect.left = this->x; + rect.right = this->x + this->width; + rect.top = this->pane1->y - CMultiSplitPane::splitBarHeight + delta; + rect.bottom = this->pane1->y + delta; + + if( rect.top < this->y ) + { + rect.top = this->y; + rect.bottom = this->y + CMultiSplitPane::splitBarHeight; + } + + if( rect.bottom >= (this->y + this->height) ) + { + rect.top = this->y + this->height - CMultiSplitPane::splitBarHeight; + rect.bottom = this->y + this->height; + } + } + else + { + rect.left = this->pane1->x - CMultiSplitPane::splitBarWidth + delta; + rect.right = this->pane1->x + delta; + rect.top = this->y; + rect.bottom = this->y + this->height; + + if( rect.left < this->x ) + { + rect.left = this->x; + rect.right = this->x + CMultiSplitPane::splitBarWidth; + } + + if( rect.right > (this->x + this->width) ) + { + rect.left = this->x + this->width - CMultiSplitPane::splitBarWidth; + rect.right = this->x + this->width; + } + } + } + } + + void moveSplitBar(int delta) + { + if( this->pane0 == NULL ) + return; + + if( delta == 0 ) + return; + + RECT rect; + this->getSplitBarRect(rect, delta); + + if( splitType == HORIZONTAL ) + { + if( this->pane1->y == rect.bottom ) + { + // move cancelled + ATLTRACE(_T("move cancelled\n")); + return; + } + + this->pane0->resize(this->width, rect.top - this->y); + this->pane1->y = rect.bottom; + this->pane1->resize(this->width, this->y + this->height - rect.bottom); + + this->splitRatio = ::MulDiv(this->pane0->height, 100, this->height - CMultiSplitPane::splitBarWidth); + } + else + { + if( this->pane1->x == rect.right ) + { + // move cancelled + ATLTRACE(_T("move cancelled\n")); + return; + } + + this->pane0->resize(rect.left - this->x, this->height); + this->pane1->x = rect.right; + this->pane1->resize(this->x + this->width - rect.right, this->height); + + this->splitRatio = ::MulDiv(this->pane0->width, 100, this->width - CMultiSplitPane::splitBarWidth); + } + } + + CMultiSplitPane* get(WHERE position) + { + POINT point; + + switch( position ) + { + case ROOT: + return this->parent ? this->parent->get(ROOT) : this; + break; + + case TOP: + point.x = this->x; + point.y = this->y - CMultiSplitPane::splitBarHeight - 1; + break; + + case BOTTOM: + point.x = this->x; + point.y = this->y + this->height + CMultiSplitPane::splitBarHeight; + break; + + case LEFT: + point.x = this->x - CMultiSplitPane::splitBarWidth - 1; + point.y = this->y; + break; + + case RIGHT: + point.x = this->x + this->width + CMultiSplitPane::splitBarWidth; + point.y = this->y; + break; + } + + return this->get(ROOT)->getPane(point); + } + + CMultiSplitPane* get(HWND window) + { + if( this->window == window ) + return this; + else if( this->pane0 ) + { + CMultiSplitPane* result = this->pane0->get(window); + if( result ) + return result; + else + return this->pane1->get(window); + } + else + return NULL; + } + + CMultiSplitPane* get(POINT point) + { + CMultiSplitPane* result = NULL; + if( this->isInRect(point) ) + { + if( this->pane0 ) + { + result = this->pane0->get(point); + if( result == NULL ) + result = this->pane1->get(point); + } + + if( result == NULL ) + result = this; + } + return result; + } + + bool isSplitBar(void) + { + return this->pane0? true : false; + } + + CMultiSplitPane* getSplitBar(POINT point) + { + CMultiSplitPane* result = this->get(point); + if( result && result->pane0 ) + return result; + else + return NULL; + } + + CMultiSplitPane* getPane(POINT point) + { + CMultiSplitPane* result = this->get(point); + if( result && result->pane0 == 0 ) + return result; + else + return NULL; + } + + void draw(CDCHandle dc) + { + if( this->pane0 ) + { + this->pane0->draw(dc); + this->pane1->draw(dc); + + RECT rect; + this->getSplitBarRect(rect, 0); + + dc.FillRect (&rect, COLOR_3DFACE); + dc.DrawEdge (&rect, EDGE_RAISED, this->splitType == VERTICAL? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM)); + } + } + + + private: + bool isInRect(POINT point) + { + if( point.x >= this->x && + (point.x - this->x) < this->width && + point.y >= this->y && + (point.y - this->y) < this->height ) + return true; + else + return false; + } + + public: + static int splitBarWidth, splitBarHeight; // splitter bar width/height (system setting) + }; + +template +class CMultiSplitImpl +{ +public : + CRect visibleRect; // visible area defined by parent + CMultiSplitPane tree; + CMultiSplitPane* defaultFocusPane;// pane to focus when splitter gets focus + CMultiSplitPane* resizingPane; // pane with splitbar moving + int resizingDelta; // splitbar delta move + int resizingDelta0; // splitbar delta on click + bool drawContentWhileResizing; // resize content while moving splitter bar (system setting) + int edgeWidth, edgeHeight; // edge width/height (system setting) + static HCURSOR vertCursor; // cursor to display on vertical splitter bar + static HCURSOR horzCursor; // cursor to display on horizontal splitter bar + +// Constructor + + CMultiSplitImpl (void) + : + defaultFocusPane (&this->tree), + resizingPane (0), + resizingDelta (0), + resizingDelta0 (0), + drawContentWhileResizing (true), + edgeWidth (0), + edgeHeight (0) + { + visibleRect.SetRectEmpty (); + + if (vertCursor == 0) + { + ::EnterCriticalSection (&_Module.m_csStaticDataInit); + if (vertCursor == 0) + vertCursor = ::LoadCursor (0, IDC_SIZEWE); + + ::LeaveCriticalSection (&_Module.m_csStaticDataInit); + } + if (horzCursor == 0) + { + ::EnterCriticalSection (&_Module.m_csStaticDataInit); + if (horzCursor == 0) + horzCursor = ::LoadCursor (0, IDC_SIZENS); + + ::LeaveCriticalSection (&_Module.m_csStaticDataInit); + } + } + +// Attributes + + void RectSet (LPRECT newRect = 0, bool update = true) + { // define visible area within parent + T * pT = static_cast (this); + + if (newRect == 0) // use all of parent's client area + pT->GetClientRect (&visibleRect);// includes edges + else + visibleRect = *newRect; + + ATLTRACE(_T("CMultiSplitImpl::RectSet: %d %d %d %d (%d %d) from %p\n"), + visibleRect.left, visibleRect.top, visibleRect.right, visibleRect.bottom, + visibleRect.Width (), visibleRect.Height (), newRect); + + if (update) + { + UpdateLayout (); + } + } + + // draw all splitter bars & empty panes, occupied panes draw themselves + + void Draw (CDCHandle dc) + { + ATLASSERT(!(dc.m_hDC == 0)); + + CPen penYellow; + penYellow.CreatePen(PS_SOLID, 1, RGB(255, 255, 0)); + dc.SelectPen(penYellow); + dc.FillSolidRect(&visibleRect, RGB(255, 0, 0)); + + int marge = 0; + dc.MoveTo(visibleRect.left + marge, visibleRect.top + marge); + dc.LineTo(visibleRect.right - 1 - marge, visibleRect.top + marge); + dc.LineTo(visibleRect.right - 1 - marge, visibleRect.bottom - 1 - marge); + dc.LineTo(visibleRect.left + marge, visibleRect.bottom - 1 - marge); + dc.LineTo(visibleRect.left + marge, visibleRect.top + marge); + dc.LineTo(visibleRect.right - 1 - marge, visibleRect.bottom - 1 - marge); + dc.MoveTo(visibleRect.right - 1 - marge, visibleRect.top + marge); + dc.LineTo(visibleRect.left + marge, visibleRect.bottom - 1 - marge); + + ATLTRACE(_T("CMultiSplitImpl::Draw: %d %d %d %d (%d %d)\n"), + visibleRect.left, visibleRect.top, visibleRect.right, visibleRect.bottom, + visibleRect.Width (), visibleRect.Height ()); + + this->tree.draw(dc); + } + +// Overrideable by derived classes + + void GhostBarDraw (void) + { + CRect BarRect; + if( this->resizingPane ) + { + this->resizingPane->getSplitBarRect(BarRect, this->resizingDelta - this->resizingDelta0); + + ATLTRACE(_T("CMultiSplitImpl::GhostBarDraw: %d %d %d %d (%d %d) delta = %d\n"), + BarRect.left, BarRect.top, BarRect.right, BarRect.bottom, + BarRect.Width (), BarRect.Height (), + this->resizingDelta); + + // invert the brush pattern (looks just like frame window sizing) + T * pT = static_cast (this); + CWindowDC dc (pT->m_hWnd); + BarRect.OffsetRect(this->edgeWidth, this->edgeHeight); + + CBrush GhostBrush = CDCHandle::GetHalftoneBrush (); + if (!GhostBrush.IsNull ()) + { + CBrushHandle OldBrush = dc.SelectBrush (GhostBrush); + dc.PatBlt (BarRect.left, BarRect.top, BarRect.Width (), BarRect.Height (), PATINVERT); + dc.SelectBrush (OldBrush); + } + } + } + +// Message map and handlers + + typedef CMultiSplitImpl< T> thisClass; + BEGIN_MSG_MAP (thisClass) + MESSAGE_HANDLER (WM_CREATE, OnCreate) + MESSAGE_HANDLER (WM_PAINT, OnPaint) +// MESSAGE_HANDLER (WM_PRINTCLIENT, OnPaint) +// if (IsInteractive ()) + { + MESSAGE_HANDLER (WM_SETCURSOR, OnSetCursor) // cursor in client area + MESSAGE_HANDLER (WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER (WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER (WM_LBUTTONUP, OnLButtonUp) +#if 0 + MESSAGE_HANDLER (WM_VSCROLL, OnScroll) // scroll bar messages + MESSAGE_HANDLER (WM_HSCROLL, OnScroll) + MESSAGE_HANDLER (WM_MOUSEWHEEL, OnMouseWheel) + MESSAGE_HANDLER (WM_LBUTTONDBLCLK, OnLButtonDoubleClick) +#endif + } + MESSAGE_HANDLER (WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER (WM_MOUSEACTIVATE, OnMouseActivate) + MESSAGE_HANDLER (WM_SETTINGCHANGE, OnSettingChange) + END_MSG_MAP () + + LRESULT OnCreate (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL & bHandled) + { + SystemSettingsGet (false); + + CRect InitRect (0, 0, ((CREATESTRUCT *) lParam)->cx, ((CREATESTRUCT *) lParam)->cy); + RectSet (&InitRect, false); + + bHandled = FALSE; + return 0; + } + + LRESULT OnPaint (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/) + { + T * pT = static_cast (this); + CPaintDC dc (pT->m_hWnd); + pT->Draw (dc.m_hDC); + return 0; + } + + LRESULT OnSetCursor (UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & bHandled) + { + T * pT = static_cast (this); + if (reinterpret_cast(wParam) == pT->m_hWnd && LOWORD (lParam) == HTCLIENT) + { + DWORD Position = ::GetMessagePos (); + POINT Point = { GET_X_LPARAM (Position), GET_Y_LPARAM (Position) }; + pT->ScreenToClient (&Point); + if ( this->tree.getSplitBar(Point) ) + return 1; + } + bHandled = FALSE; + return 0; + } + + // Dragging splitbar resizes panes to either side of bar + // Pane size is checked and changed on every receipt of this message. + + LRESULT OnMouseMove (UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & bHandled) + { + T * pT = static_cast (this); + POINT Point = { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) }; + if ((wParam & MK_LBUTTON) && ::GetCapture () == pT->m_hWnd) + { // resizing + int delta = resizingPane->getSplitBarDelta(Point); + + if ( delta ) + { + if (drawContentWhileResizing) + { + resizingPane->moveSplitBar(delta - this->resizingDelta0); + pT->InvalidateRect(NULL); + pT->UpdateWindow (); + } + else + { + GhostBarDraw (); + this->resizingDelta = delta; + GhostBarDraw (); + } + } + } + else + { // not dragging, just set cursor + CMultiSplitPane* splitBar = this->tree.getSplitBar(Point); + if ( splitBar ) + ::SetCursor (splitBar->splitType == CMultiSplitPane::VERTICAL ? vertCursor : horzCursor); + + bHandled = FALSE; + } + return 0; + } + + // start splitbar drag + + LRESULT OnLButtonDown (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL & bHandled) + { + POINT Point = { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) }; + this->resizingPane = this->tree.getSplitBar(Point); + if( resizingPane ) + { + this->resizingDelta0 = this->resizingDelta = resizingPane->getSplitBarDelta(Point); + T * pT = static_cast (this); + pT->SetCapture (); + ::SetCursor (resizingPane->splitType == CMultiSplitPane::VERTICAL ? vertCursor : horzCursor); + if (!drawContentWhileResizing) + GhostBarDraw (); + } + bHandled = FALSE; + return 1; + } + + // end splitbar drag + + LRESULT OnLButtonUp (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & bHandled) + { + if( this->resizingPane && !drawContentWhileResizing) + { + GhostBarDraw (); + T * pT = static_cast (this); + resizingPane->moveSplitBar(this->resizingDelta - this->resizingDelta0); + pT->InvalidateRect(NULL); + pT->UpdateWindow (); + } + this->resizingPane = 0; + ::ReleaseCapture (); + bHandled = FALSE; + return 1; + } + + LRESULT OnSetFocus (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL & bHandled) + { // give focus to defaultPane child +// ATLTRACE(_T("CMultiSplitImpl::OnSetFocus: %p\n"), defaultFocusPane); + if( defaultFocusPane && defaultFocusPane->window ) + ::SetFocus(defaultFocusPane->window); + + bHandled = FALSE; + return 1; + } + + LRESULT OnMouseActivate (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & /*bHandled*/) + { + T * pT = static_cast (this); + LRESULT Result = pT->DefWindowProc (uMsg, wParam, lParam); +/* LPCTSTR Text; + switch (Result) + { + case MA_ACTIVATE : + Text = _T("MA_ACTIVATE"); + break; + case MA_ACTIVATEANDEAT : + Text = _T("MA_ACTIVATEANDEAT"); + break; + case MA_NOACTIVATE : + Text = _T("MA_NOACTIVATE"); + break; + case MA_NOACTIVATEANDEAT : + Text = _T("MA_NOACTIVATEANDEAT"); + break; + } + ATLTRACE(_T("CMultiSplitImpl::OnMouseActivate: %s\n"), Text); +*/ + if (Result == MA_ACTIVATE || Result == MA_ACTIVATEANDEAT) + { // select focus pane from mouse position + DWORD Position = ::GetMessagePos (); + POINT Point = { GET_X_LPARAM (Position), GET_Y_LPARAM (Position) }; + pT->ScreenToClient (&Point); + + this->defaultFocusPane = this->tree.getPane(Point); + pT->SetFocus (); // focus child window + ATLTRACE(_T("CMultiSplitImpl::OnMouseActivate: defaultFocusPane = %p\n"), this->defaultFocusPane); + } + return Result; + } + + LRESULT OnSettingChange (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/) + { + SystemSettingsGet (true); + return 0; + } + +// Implementation - internal helpers + + // Invalidate splitter bar areas and empty spaces, set child window pane positions & sizes. + // Calculate contentSize. + // Called whenever SystemSettings changed, RectSet, LButtonUp, child windows changed + + void UpdateLayout (void) + { + T * pT = static_cast (this); + pT->InvalidateRect(NULL); + this->tree.resize(this->visibleRect.Width(), this->visibleRect.Height()); + } + + + // get the bar & edge widthssplitBarWidth + + void SystemSettingsGet (bool update) + { + CMultiSplitPane::splitBarWidth = ::GetSystemMetrics (SM_CXSIZEFRAME); + CMultiSplitPane::splitBarHeight = ::GetSystemMetrics (SM_CYSIZEFRAME); + + this->edgeWidth = ::GetSystemMetrics (SM_CXEDGE); + this->edgeHeight = ::GetSystemMetrics (SM_CYEDGE); + + ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &drawContentWhileResizing, 0); + drawContentWhileResizing = false; + + T * pT = static_cast (this); + if (update && pT->IsWindow ()) + { + UpdateLayout (); + pT->UpdateWindow (); + } + } + +}; + + +template HCURSOR CMultiSplitImpl::vertCursor = 0; +template HCURSOR CMultiSplitImpl::horzCursor = 0; + + +///////////////////////////////////////////////////////////////////////////// +// CMultiSplitWindowImpl - Implements a splitter window + +template +class ATL_NO_VTABLE CMultiSplitWindowImpl +: public CWindowImpl< T, TBase, TWinTraits >, + public CMultiSplitImpl< T > +{ +public : + DECLARE_WND_CLASS_EX(0, CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, COLOR_WINDOW) + + typedef CMultiSplitWindowImpl< T , TBase, TWinTraits > thisClass; + typedef CMultiSplitImpl< T > baseClass; + BEGIN_MSG_MAP (thisClass) + MESSAGE_HANDLER (WM_ERASEBKGND, OnEraseBackground) + MESSAGE_HANDLER (WM_SIZE, OnSize) + CHAIN_MSG_MAP (baseClass) + FORWARD_NOTIFICATIONS () + END_MSG_MAP () + + LRESULT OnEraseBackground (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/) + { + return 1; // handled, no background painting needed + } + + LRESULT OnSize (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL & /*bHandled*/) + { + CRect Rect (0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + RectSet (&Rect); + return 0; // handled + } +}; + + +///////////////////////////////////////////////////////////////////////////// +// CMultiSplitWindow - Implements a splitter window to be used as is + +class CMultiSplitWindow : public CMultiSplitWindowImpl +{ +public : + DECLARE_WND_CLASS_EX (_T ("MultiSplitWindow"), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, COLOR_WINDOW) +}; + + +}; //namespace WTL + + +#endif // __ATLMULTISPLIT_H__ From 2f0b959220de24321ebf775f80ad802f43592014 Mon Sep 17 00:00:00 2001 From: cbucher Date: Tue, 9 Aug 2011 17:13:12 +0200 Subject: [PATCH 080/207] add keyboard shortcuts: "Next view" "Previous view" "Close view" "Split horizontally" "Split vertically" "Group all" "Ungroup all" "Group tab" "Ungroup tab" show the GetActiveConsole caller in trace optimize GetActiveConsole calls in TabView::PreTranslateMessage --- Console/Console.rc | 15 ++++- Console/MainFrame.cpp | 124 ++++++++++++++++++++++++++++++++---- Console/MainFrame.h | 21 +++++- Console/SettingsHandler.cpp | 10 +++ Console/TabView.cpp | 77 ++++++++++++++++++++-- Console/TabView.h | 6 +- Console/console.xml | 9 +++ Console/resource.h | 9 +++ 8 files changed, 251 insertions(+), 20 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index b3340adc..555c5b28 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -313,7 +313,7 @@ BEGIN CONTROL "Bo&rder *",IDC_CHECK_STYLE_BORDER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,36,43,10 CONTROL "Tas&kbar button *",IDC_CHECK_STYLE_TASKBAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,12,68,10 CONTROL "Tra&y icon",IDC_CHECK_STYLE_TRAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,24,45,10 - CONTROL "Quake like",IDC_CHECK_STYLE_QUAKE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,36,49,10 + CONTROL "Quake like",IDC_CHECK_STYLE_QUAKE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,36,49,10 LTEXT "Inside &border:",IDC_STATIC,102,53,46,8 EDITTEXT IDC_INSIDE_BORDER,153,50,33,14,ES_AUTOHSCROLL CONTROL "",IDC_SPIN_INSIDE_BORDER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,191,50,11,14 @@ -953,6 +953,11 @@ STRINGTABLE BEGIN ID_NEXT_TAB "Switch to next tab\nNext tab" ID_PREV_TAB "Switch to previous tab\nPrevious tab" + ID_NEXT_VIEW "Switch to the next view\nNext View" + ID_PREV_VIEW "Switch to the previous view\nPrevious View" + ID_CLOSE_VIEW "Close the current view\nClose View" + ID_SPLIT_HORIZ "Split the current view horizontally\nSplit Horizontally" + ID_SPLIT_VERT "Split the current view vertically\nSplit Vertically" END STRINGTABLE @@ -966,6 +971,14 @@ BEGIN IDS_ERR_CANT_START_SHELL_AS_USER "Unable to start a %1% as user %2%!" END +STRINGTABLE +BEGIN + ID_GROUP_ALL "Group all terminals so that any input sent to one of them, goes to all of them\nGroup All" + ID_UNGROUP_ALL "Remove grouping from all terminals\nUngroup All" + ID_GROUP_TAB "Group all terminals in the current tab so that any input sent to one of them, goes to all of them\nGroup Tab" + ID_UNGROUP_TAB "Remove grouping of all terminals in the current tab\nUngroup Tab" +END + #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 4ab94347..e97466f4 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -91,7 +91,7 @@ BOOL MainFrame::OnIdle() if (m_activeTabView) { - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { UIEnable(ID_EDIT_COPY, activeConsoleView->CanCopy() ? TRUE : FALSE); @@ -819,7 +819,7 @@ LRESULT MainFrame::OnUpdateTitles(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam* if (itView == m_tabs.end()) return 0; shared_ptr tabView(itView->second); - shared_ptr consoleView = itView->second->GetActiveConsole(); + shared_ptr consoleView = itView->second->GetActiveConsole(_T(__FUNCTION__)); if (!consoleView) return 0; WindowSettings& windowSettings = g_settingsHandler->GetAppearanceSettings().windowSettings; @@ -1022,7 +1022,7 @@ LRESULT MainFrame::OnTabChanged(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) if (appearanceSettings.windowSettings.bUseTabTitles && m_activeTabView) { - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { SetWindowText(activeConsoleView->GetTitle()); @@ -1189,6 +1189,108 @@ LRESULT MainFrame::OnPrevTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl* ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnNextView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + MessageBox(_T(__FUNCTION__)); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnPrevView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + MessageBox(_T(__FUNCTION__)); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnCloseView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if( m_activeTabView ) + m_activeTabView->CloseView(); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnSplitHorizontally(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if( m_activeTabView ) + m_activeTabView->SplitHorizontally(); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnSplitVertically(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + if( m_activeTabView ) + m_activeTabView->SplitVertically(); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + MessageBox(_T(__FUNCTION__)); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnUngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + MessageBox(_T(__FUNCTION__)); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnGroupTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + MessageBox(_T(__FUNCTION__)); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////// + +LRESULT MainFrame::OnUngroupTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + MessageBox(_T(__FUNCTION__)); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) @@ -1205,7 +1307,7 @@ LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { if (!m_activeTabView) return 0; - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { activeConsoleView->Paste(); @@ -1222,7 +1324,7 @@ LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, LRESULT MainFrame::OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { if (!m_activeTabView) return 0; - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { activeConsoleView->Copy(); @@ -1239,7 +1341,7 @@ LRESULT MainFrame::OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { if (!m_activeTabView) return 0; - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { activeConsoleView->ClearSelection(); @@ -1256,7 +1358,7 @@ LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { if (!m_activeTabView) return 0; - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { activeConsoleView->Paste(); @@ -1273,7 +1375,7 @@ LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt LRESULT MainFrame::OnEditStopScrolling(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { if (!m_activeTabView) return 0; - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { activeConsoleView->GetConsoleHandler().StopScrolling(); @@ -1433,7 +1535,7 @@ LRESULT MainFrame::OnViewConsole(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWnd { if (m_activeTabView) { - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { activeConsoleView->SetConsoleWindowVisible(!activeConsoleView->GetConsoleWindowVisible()); @@ -1465,7 +1567,7 @@ LRESULT MainFrame::OnDumpBuffer(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndC { if (m_activeTabView) { - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { activeConsoleView->DumpBuffer(); @@ -1709,7 +1811,7 @@ void MainFrame::UpdateStatusBar() if (m_activeTabView) { - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(); + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); if( activeConsoleView ) { SharedMemory& consoleParams = activeConsoleView->GetConsoleHandler().GetConsoleParams(); diff --git a/Console/MainFrame.h b/Console/MainFrame.h index b2b58c67..083db2c0 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -101,6 +101,15 @@ class MainFrame COMMAND_RANGE_HANDLER(ID_SWITCH_TAB_1, ID_SWITCH_TAB_1 + 9, OnSwitchTab) COMMAND_ID_HANDLER(ID_NEXT_TAB, OnNextTab) COMMAND_ID_HANDLER(ID_PREV_TAB, OnPrevTab) + COMMAND_ID_HANDLER(ID_NEXT_VIEW , OnNextView) + COMMAND_ID_HANDLER(ID_PREV_VIEW , OnPrevView) + COMMAND_ID_HANDLER(ID_CLOSE_VIEW , OnCloseView) + COMMAND_ID_HANDLER(ID_SPLIT_HORIZ , OnSplitHorizontally) + COMMAND_ID_HANDLER(ID_SPLIT_VERT , OnSplitVertically) + COMMAND_ID_HANDLER(ID_GROUP_ALL , OngroupAll) + COMMAND_ID_HANDLER(ID_UNGROUP_ALL , OnUngroupAll) + COMMAND_ID_HANDLER(ID_GROUP_TAB , OnGroupTab) + COMMAND_ID_HANDLER(ID_UNGROUP_TAB , OnUngroupTab) COMMAND_ID_HANDLER(ID_FILE_CLOSE_TAB, OnFileCloseTab) COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit) COMMAND_ID_HANDLER(ID_EDIT_COPY, OnEditCopy) @@ -167,6 +176,16 @@ class MainFrame LRESULT OnNextTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnPrevTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnNextView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnPrevView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnCloseView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnSplitHorizontally(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnSplitVertically(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnUngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnGroupTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnUngroupTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); @@ -193,12 +212,12 @@ class MainFrame void SetSelectionSize(int iSelectionSize); void AdjustWindowSize(bool bResizeConsole); void RecreateOffscreenBuffers(); + void CloseTab(HWND hwndTabView); private: bool CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir = wstring(L""), const wstring& strStartupCmd = wstring(L"")); void CloseTab(CTabViewTabItem* pTabItem); - void CloseTab(HWND hwndTabView); void UpdateTabTitle(HWND hwndTabView, CString& strTabTitle); void UpdateTabsMenu(CMenuHandle mainMenu, CMenu& tabsMenu); diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index ba5eb88f..1b725685 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -1052,6 +1052,16 @@ HotKeys::HotKeys() commands.push_back(shared_ptr(new CommandData(L"closetab", ID_FILE_CLOSE_TAB, L"Close tab"))); commands.push_back(shared_ptr(new CommandData(L"renametab", ID_EDIT_RENAME_TAB, L"Rename tab"))); + commands.push_back(shared_ptr(new CommandData(L"nextview", ID_NEXT_VIEW, L"Next view"))); + commands.push_back(shared_ptr(new CommandData(L"prevview", ID_PREV_VIEW, L"Previous view"))); + commands.push_back(shared_ptr(new CommandData(L"closeview", ID_CLOSE_VIEW, L"Close view"))); + commands.push_back(shared_ptr(new CommandData(L"splithoriz", ID_SPLIT_HORIZ, L"Split horizontally"))); + commands.push_back(shared_ptr(new CommandData(L"splitvert", ID_SPLIT_VERT, L"Split vertically"))); + commands.push_back(shared_ptr(new CommandData(L"groupall", ID_GROUP_ALL, L"Group all"))); + commands.push_back(shared_ptr(new CommandData(L"ungroupall", ID_UNGROUP_ALL, L"Ungroup all"))); + commands.push_back(shared_ptr(new CommandData(L"grouptab", ID_GROUP_TAB, L"Group tab"))); + commands.push_back(shared_ptr(new CommandData(L"ungrouptab", ID_UNGROUP_TAB, L"Ungroup tab"))); + commands.push_back(shared_ptr(new CommandData(L"copy", ID_EDIT_COPY, L"Copy selection"))); commands.push_back(shared_ptr(new CommandData(L"clear_selection",ID_EDIT_CLEAR_SELECTION, L"Clear selection"))); commands.push_back(shared_ptr(new CommandData(L"paste", ID_EDIT_PASTE, L"Paste"))); diff --git a/Console/TabView.cpp b/Console/TabView.cpp index 936e9e6d..0da32725 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -1,8 +1,10 @@ #include "stdafx.h" +#include "resource.h" #include "Console.h" #include "TabView.h" #include "DlgCredentials.h" +#include "MainFrame.h" int CMultiSplitPane::splitBarWidth = 0; int CMultiSplitPane::splitBarHeight = 0; @@ -36,10 +38,29 @@ TabView::~TabView() BOOL TabView::PreTranslateMessage(MSG* pMsg) { - shared_ptr consoleView = this->GetActiveConsole(); + if ((pMsg->message == WM_KEYDOWN) || + (pMsg->message == WM_KEYUP) || + (pMsg->message == WM_SYSKEYDOWN) || + (pMsg->message == WM_SYSKEYUP)) + { + // Avoid calling ::TranslateMessage for WM_KEYDOWN, WM_KEYUP, + // WM_SYSKEYDOWN and WM_SYSKEYUP (except for wParam == VK_PACKET, + // which is sent by SendInput when pasting text). + /// + // This prevents WM_CHAR and WM_SYSCHAR messages, enabling stuff like + // handling 'dead' characters input and passing all keys to console. + if (pMsg->wParam == VK_PACKET) return FALSE; + ::DispatchMessage(pMsg); + return TRUE; + } + + return FALSE; + /* + shared_ptr consoleView = this->GetActiveConsole(_T(__FUNCTION__)); if( consoleView ) return consoleView->PreTranslateMessage(pMsg); return FALSE; + */ } ////////////////////////////////////////////////////////////////////////////// @@ -189,13 +210,13 @@ HWND TabView::CreateNewConsole(void) return hwndConsoleView; } -shared_ptr TabView::GetActiveConsole() +shared_ptr TabView::GetActiveConsole(const TCHAR* szFrom) { shared_ptr result; - if( this->defaultFocusPane && defaultFocusPane->window ) + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) { MutexLock viewMapLock(m_viewsMutex); - ConsoleViewMap::iterator iter = m_views.find(defaultFocusPane->window); + ConsoleViewMap::iterator iter = m_views.find(multisplitClass::defaultFocusPane->window); if( iter != m_views.end() ) result = iter->second; else @@ -203,9 +224,9 @@ shared_ptr TabView::GetActiveConsole() } else { - TRACE(L"TabView::GetActiveConsole this->defaultFocusPane = %p\n", this->defaultFocusPane); + TRACE(L"TabView::GetActiveConsole multisplitClass::defaultFocusPane = %p\n", multisplitClass::defaultFocusPane); } - TRACE(L"TabView::GetActiveConsole returns %p\n", result.get()); + TRACE(L"TabView::GetActiveConsole called by %s returns %p\n", szFrom, result.get()); return result; } @@ -295,4 +316,48 @@ void TabView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge) { it->second->AdjustRectAndResize(clientRect, dwResizeWindowEdge); } + this->GetRect(clientRect); +} + +void TabView::SplitHorizontally() +{ + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) + { + HWND hwndConsoleView = CreateNewConsole(); + if( hwndConsoleView ) + { + multisplitClass::defaultFocusPane = multisplitClass::defaultFocusPane->split( + hwndConsoleView, + CMultiSplitPane::HORIZONTAL); + } + } +} + +void TabView::SplitVertically() +{ + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) + { + HWND hwndConsoleView = CreateNewConsole(); + if( hwndConsoleView ) + { + multisplitClass::defaultFocusPane = multisplitClass::defaultFocusPane->split( + hwndConsoleView, + CMultiSplitPane::VERTICAL); + } + } +} + +void TabView::CloseView() +{ + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) + { + MutexLock viewMapLock(m_viewsMutex); + ConsoleViewMap::iterator iter = m_views.find(multisplitClass::defaultFocusPane->window); + iter->second->DestroyWindow(); + m_views.erase(iter); + multisplitClass::defaultFocusPane->remove(); + + if( m_views.size() == 0 ) + m_mainFrame.CloseTab(this->m_hWnd); + } } \ No newline at end of file diff --git a/Console/TabView.h b/Console/TabView.h index 2086d007..f000192d 100644 --- a/Console/TabView.h +++ b/Console/TabView.h @@ -34,7 +34,7 @@ class TabView LRESULT OnEraseBackground (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/); LRESULT OnSize (UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL & bHandled); - shared_ptr GetActiveConsole(); + shared_ptr GetActiveConsole(const TCHAR*); shared_ptr GetTabData() { return m_tabData; } void SetTitle(const CString& strTitle); @@ -50,6 +50,10 @@ class TabView void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge); void GetRect(CRect& clientRect); + void SplitHorizontally(); + void SplitVertically(); + void CloseView(); + private: HWND CreateNewConsole(void); diff --git a/Console/console.xml b/Console/console.xml index 9d1bd0df..15317bb2 100644 --- a/Console/console.xml +++ b/Console/console.xml @@ -66,6 +66,15 @@ + + + + + + + + + diff --git a/Console/resource.h b/Console/resource.h index 28c82ab3..39b0146e 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -233,6 +233,15 @@ #define ID_NEXT_TAB 2200 #define ID_PREV_TAB 2201 #define ID_RENAME_TAB_OK 2202 +#define ID_NEXT_VIEW 2203 +#define ID_PREV_VIEW 2204 +#define ID_CLOSE_VIEW 2205 +#define ID_SPLIT_HORIZ 2206 +#define ID_SPLIT_VERT 2207 +#define ID_GROUP_ALL 2208 +#define ID_UNGROUP_ALL 2209 +#define ID_GROUP_TAB 2210 +#define ID_UNGROUP_TAB 2211 #define IDC_DUMP_BUFFER 3000 #define IDS_ERR_CANT_START_SHELL 5000 #define IDS_ERR_CANT_START_AS_USER 5001 From 25272ab7767d807aa84a925e4cb0d546e184432a Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 14 Aug 2011 15:24:59 +0200 Subject: [PATCH 081/207] mod inside broders are no longer variable mod console rect is calculated if size is zero mod offscreen and text are no longer static fix console starting size is calculated fix tabView::OnSize has no effects until Mainframe create is done --- Console/ConsoleView.cpp | 127 +++++++++++++++++++++++++--------------- Console/ConsoleView.h | 23 ++++---- Console/MainFrame.cpp | 5 +- Console/MainFrame.h | 7 +-- Console/TabView.cpp | 17 ++++-- 5 files changed, 108 insertions(+), 71 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index b133a120..17ed399f 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -15,16 +15,20 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -CDC ConsoleView::m_dcOffscreen(::CreateCompatibleDC(NULL)); -CDC ConsoleView::m_dcText(::CreateCompatibleDC(NULL)); +//CDC ConsoleView::m_dcOffscreen(::CreateCompatibleDC(NULL)); +//CDC ConsoleView::m_dcText(::CreateCompatibleDC(NULL)); -CBitmap ConsoleView::m_bmpOffscreen; -CBitmap ConsoleView::m_bmpText; +//CBitmap ConsoleView::m_bmpOffscreen; +//CBitmap ConsoleView::m_bmpText; -CFont ConsoleView::m_fontText; +CFont ConsoleView::m_fontText; -int ConsoleView::m_nCharHeight(0); -int ConsoleView::m_nCharWidth(0); +int ConsoleView::m_nCharHeight(0); +int ConsoleView::m_nCharWidth(0); +int ConsoleView::m_nVScrollWidth(0); +int ConsoleView::m_nHScrollWidth(0); +int ConsoleView::m_nVInsideBorder(0); +int ConsoleView::m_nHInsideBorder(0); ////////////////////////////////////////////////////////////////////////////// @@ -43,10 +47,6 @@ ConsoleView::ConsoleView(MainFrame& mainFrame, HWND hwndTabView, shared_ptrdwColumns * m_nCharWidth + 2 * m_nVInsideBorder; - clientRect.bottom = m_consoleHandler.GetConsoleParams()->dwRows * m_nCharHeight + 2 * m_nHInsideBorder; + RECT rect; + GetWindowRect(&rect); - if (m_bShowVScroll) clientRect.right += m_nVScrollWidth; - if (m_bShowHScroll) clientRect.bottom += m_nHScrollWidth; + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + + clientRect.left = 0; + clientRect.top = 0; + clientRect.right = m_consoleHandler.GetConsoleParams()->dwColumns * m_nCharWidth + 2 * m_nVInsideBorder; + clientRect.bottom = m_consoleHandler.GetConsoleParams()->dwRows * m_nCharHeight + 2 * m_nHInsideBorder; + + if (m_bShowVScroll) clientRect.right += m_nVScrollWidth; + if (m_bShowHScroll) clientRect.bottom += m_nHScrollWidth; + + if( width > clientRect.right ) clientRect.right = width; + if( height > clientRect.bottom ) clientRect.bottom = height; + + TRACE(L"========ConsoleView::GetRect=====================================\n"); + TRACE(L"wind: %ix%i - %ix%i\n", rect.left, rect.top, rect.right, rect.bottom); + TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); } ////////////////////////////////////////////////////////////////////////////// @@ -967,32 +983,41 @@ void ConsoleView::GetRect(CRect& clientRect) void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge) { - GetWindowRect(&clientRect); -/* - TRACE(L"================================================================\n"); - TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); -*/ + GetWindowRect(&clientRect); + + TRACE(L"========AdjustRectAndResize=====================================\n"); + TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + LONG width = clientRect.right - clientRect.left; LONG height = clientRect.bottom - clientRect.top; - // exclude scrollbars from row/col calculation - if (m_bShowVScroll) width -= m_nVScrollWidth; - if (m_bShowHScroll) height -= m_nHScrollWidth; + // exclude scrollbars from row/col calculation + if (m_bShowVScroll) width -= m_nVScrollWidth; + if (m_bShowHScroll) height -= m_nHScrollWidth; + + // exclude inside borders from row/col calculation + width -= (m_nVInsideBorder * 2); + height -= (m_nHInsideBorder * 2); + + TRACE(L"exclude scrollbars and inside borders from row/col calculation\n"); + TRACE(L"width: %i height: %i\n", width, height); DWORD dwColumns = width / m_nCharWidth; DWORD dwRows = height / m_nCharHeight; + TRACE(L"m_nCharWidth: %i m_nCharHeight: %i\n", m_nCharWidth, m_nCharHeight); + DWORD dwMaxColumns = this->m_consoleHandler.GetConsoleParams()->dwMaxColumns; DWORD dwMaxRows = this->m_consoleHandler.GetConsoleParams()->dwMaxRows; + TRACE(L"dwMaxColumns: %i dwMaxRows: %i\n", dwMaxColumns, dwMaxRows); + if( dwColumns > dwMaxColumns ) dwColumns = dwMaxColumns; if( dwRows > dwMaxRows ) dwRows = dwMaxRows; - // variable inside borders - m_nVInsideBorder = (width - dwColumns * m_nCharWidth ) / 2; - m_nHInsideBorder = (height - dwRows * m_nCharHeight) / 2; + TRACE(L"dwColumns: %i dwRows: %i\n", dwColumns, dwRows); clientRect.right = clientRect.left + dwColumns * m_nCharWidth + m_nVInsideBorder * 2; clientRect.bottom = clientRect.top + dwRows * m_nCharHeight + m_nHInsideBorder * 2; @@ -1001,19 +1026,17 @@ void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdg if (m_bShowVScroll) clientRect.right += m_nVScrollWidth; if (m_bShowHScroll) clientRect.bottom += m_nHScrollWidth; - SharedMemory& newConsoleSize = m_consoleHandler.GetNewConsoleSize(); - SharedMemoryLock memLock(newConsoleSize); + SharedMemory& newConsoleSize = m_consoleHandler.GetNewConsoleSize(); + SharedMemoryLock memLock(newConsoleSize); - newConsoleSize->dwColumns = dwColumns; - newConsoleSize->dwRows = dwRows; - newConsoleSize->dwResizeWindowEdge = dwResizeWindowEdge; + newConsoleSize->dwColumns = dwColumns; + newConsoleSize->dwRows = dwRows; + newConsoleSize->dwResizeWindowEdge = dwResizeWindowEdge; -/* - TRACE(L"console view: 0x%08X, adjusted: %ix%i\n", m_hWnd, dwRows, dwColumns); - TRACE(L"================================================================\n"); -*/ + TRACE(L"console view: 0x%08X, adjusted: %ix%i\n", m_hWnd, dwRows, dwColumns); + TRACE(L"================================================================\n"); - m_consoleHandler.GetNewConsoleSize().SetReqEvent(); + m_consoleHandler.GetNewConsoleSize().SetReqEvent(); } ////////////////////////////////////////////////////////////////////////////// @@ -1077,6 +1100,7 @@ void ConsoleView::RecreateOffscreenBuffers() void ConsoleView::Repaint(bool bFullRepaint) { + TRACE(L"ConsoleView::Repaint\n"); // OnPaint will do the work for a full repaint if (!m_bNeedFullRepaint) { @@ -1369,6 +1393,7 @@ void ConsoleView::CreateOffscreenBuffers() // create offscreen bitmaps if needed if (m_bmpOffscreen.IsNull()) CreateOffscreenBitmap(m_dcOffscreen, rectWindowMax, m_bmpOffscreen); if (m_bmpText.IsNull()) CreateOffscreenBitmap(m_dcText, rectWindowMax, m_bmpText); + m_dcText.SelectFont(m_fontText); // create background brush m_backgroundBrush.CreateSolidBrush(m_tabData->crBackgroundColor); @@ -1429,6 +1454,8 @@ bool ConsoleView::CreateFont(const wstring& strFontName) { if (!m_fontText.IsNull()) return true;// m_fontText.DeleteObject(); + CDC dcText(::CreateCompatibleDC(NULL)); + BYTE byFontQuality = DEFAULT_QUALITY; switch (g_settingsHandler->GetAppearanceSettings().fontSettings.fontSmoothing) @@ -1439,7 +1466,7 @@ bool ConsoleView::CreateFont(const wstring& strFontName) default : DEFAULT_QUALITY; } m_fontText.CreateFont( - -::MulDiv(g_settingsHandler->GetAppearanceSettings().fontSettings.dwSize , m_dcText.GetDeviceCaps(LOGPIXELSY), 72), + -::MulDiv(g_settingsHandler->GetAppearanceSettings().fontSettings.dwSize , dcText.GetDeviceCaps(LOGPIXELSY), 72), 0, 0, 0, @@ -1456,8 +1483,8 @@ bool ConsoleView::CreateFont(const wstring& strFontName) TEXTMETRIC textMetric; - m_dcText.SelectFont(m_fontText); - m_dcText.GetTextMetrics(&textMetric); + dcText.SelectFont(m_fontText); + dcText.GetTextMetrics(&textMetric); if (textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) { @@ -1468,10 +1495,13 @@ bool ConsoleView::CreateFont(const wstring& strFontName) // fixed pitch font (TMPF_FIXED_PITCH is cleared!!!) m_nCharWidth = textMetric.tmAveCharWidth; m_nCharHeight = textMetric.tmHeight; -#if 0 + + m_nVScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL); + m_nHScrollWidth = ::GetSystemMetrics(SM_CXHSCROLL); + m_nVInsideBorder = g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder; m_nHInsideBorder = g_settingsHandler->GetAppearanceSettings().stylesSettings.dwInsideBorder; -#endif + return true; } @@ -1673,6 +1703,10 @@ void ConsoleView::RepaintText(CDC& dc) bitmapRect.right = bitmapSize.cx; bitmapRect.bottom = bitmapSize.cy; + SIZE bitmapSize2; + m_dcOffscreen.GetCurrentBitmap().GetSize(bitmapSize2); + TRACE(L"ConsoleView::RepaintText (%ix%i on %ix%i)\n", bitmapSize.cx, bitmapSize.cy, bitmapSize2.cx, bitmapSize2.cy); + if (m_tabData->backgroundImageType == bktypeNone) { dc.FillRect(&bitmapRect, m_backgroundBrush); @@ -1682,6 +1716,9 @@ void ConsoleView::RepaintText(CDC& dc) CRect rectWindow; GetClientRect(&rectWindow); + TRACE(L"========UpdateImageBitmap=====================================\n"); + TRACE(L"rect: %ix%i - %ix%i\n", rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom); + g_imageHandler->UpdateImageBitmap(dc, rectWindow, m_background); if (m_tabData->imageData.bRelative) @@ -1846,6 +1883,7 @@ void ConsoleView::RepaintText(CDC& dc) void ConsoleView::RepaintTextChanges(CDC& dc) { + TRACE(L"ConsoleView::RepaintTextChanges\n"); DWORD dwX = m_nVInsideBorder; DWORD dwY = m_nHInsideBorder; DWORD dwOffset = 0; @@ -2285,6 +2323,3 @@ COORD ConsoleView::GetConsoleCoord(const CPoint& clientPoint, bool bStartSelecti return consolePoint; } - -///////////////////////////////////////////////////////////////////////////// - diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index dd5fe551..da816e00 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -96,7 +96,6 @@ class ConsoleView LRESULT OnScrollCommand(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& bHandled); - public: void GetRect(CRect& clientRect); @@ -187,10 +186,6 @@ class ConsoleView bool m_bShowVScroll; bool m_bShowHScroll; - int m_nVScrollWidth; - int m_nHScrollWidth; - int m_nVInsideBorder; - int m_nHInsideBorder; CString m_strTitle; CString m_strUser; @@ -226,16 +221,20 @@ class ConsoleView // static members private: - static CDC m_dcOffscreen; - static CDC m_dcText; + /*static*/ CDC m_dcOffscreen; + /*static*/ CDC m_dcText; - static CBitmap m_bmpOffscreen; - static CBitmap m_bmpText; + /*static*/ CBitmap m_bmpOffscreen; + /*static*/ CBitmap m_bmpText; - static CFont m_fontText; + static CFont m_fontText; - static int m_nCharHeight; - static int m_nCharWidth; + static int m_nCharHeight; + static int m_nCharWidth; + static int m_nVScrollWidth; + static int m_nHScrollWidth; + static int m_nVInsideBorder; + static int m_nHInsideBorder; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index e97466f4..e928aaf9 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -2128,6 +2128,7 @@ void MainFrame::ResizeWindow() void MainFrame::AdjustWindowSize(bool bResizeConsole) { + TRACE(L"AdjustWindowSize\n"); CRect clientRect(0, 0, 0, 0); if( this->IsZoomed() ) @@ -2169,7 +2170,7 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole) AdjustWindowRect(clientRect); -// TRACE(L"AdjustWindowSize: %ix%i\n", clientRect.Width(), clientRect.Height()); + TRACE(L"AdjustWindowSize 1: %ix%i\n", clientRect.Width(), clientRect.Height()); SetWindowPos( 0, 0, @@ -2182,7 +2183,7 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole) CRect rectWindow; GetWindowRect(&rectWindow); -// TRACE(L"AdjustWindowSize 2: %ix%i\n", rectWindow.Width(), rectWindow.Height()); + TRACE(L"AdjustWindowSize 2: %ix%i\n", rectWindow.Width(), rectWindow.Height()); m_dwWindowWidth = rectWindow.Width(); m_dwWindowHeight= rectWindow.Height(); diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 083db2c0..5397d1a1 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -243,10 +243,10 @@ class MainFrame void CreateStatusBar(); BOOL SetTrayIcon(DWORD dwMessage); - private: + public: bool m_bOnCreateDone; - + private: const vector& m_startupTabs; const vector& m_startupDirs; const vector& m_startupCmds; @@ -287,9 +287,6 @@ class MainFrame CAccelerator m_acceleratorTable; CMultiPaneStatusBarCtrl m_statusBar; - CDC m_dcOffscreen; - CDC m_dcText; - MARGINS m_Margins; }; diff --git a/Console/TabView.cpp b/Console/TabView.cpp index 0da32725..290a7aa5 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -86,6 +86,9 @@ LRESULT TabView::OnCreate (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHand if( result == 0 ) { multisplitClass::tree.window = hwndConsoleView; + CRect rect; + m_views.begin()->second->GetRect(rect); + multisplitClass::RectSet(rect, true); } } @@ -100,13 +103,15 @@ LRESULT TabView::OnEraseBackground (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*l return 1; } -LRESULT TabView::OnSize (UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL & bHandled) +LRESULT TabView::OnSize (UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & bHandled) { - if (wParam != SIZE_MINIMIZED) - RectSet (); // to ClientRect + if (wParam != SIZE_MINIMIZED && m_mainFrame.m_bOnCreateDone) + { + multisplitClass::RectSet(); // to ClientRect + } - bHandled = FALSE; - return 1; + bHandled = FALSE; + return 1; } HWND TabView::CreateNewConsole(void) @@ -226,7 +231,7 @@ shared_ptr TabView::GetActiveConsole(const TCHAR* szFrom) { TRACE(L"TabView::GetActiveConsole multisplitClass::defaultFocusPane = %p\n", multisplitClass::defaultFocusPane); } - TRACE(L"TabView::GetActiveConsole called by %s returns %p\n", szFrom, result.get()); + //TRACE(L"TabView::GetActiveConsole called by %s returns %p\n", szFrom, result.get()); return result; } From 452e58cb4b7843f678e14b2d69ad9f6b3b93cd2d Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 14 Aug 2011 17:24:31 +0200 Subject: [PATCH 082/207] fix AppActive when switching between panes --- Console/TabView.cpp | 23 +++++++++++++++++------ Console/TabView.h | 5 +++++ wtl/wtl/include/multisplit.h | 14 +++++++++++++- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Console/TabView.cpp b/Console/TabView.cpp index 290a7aa5..49b28c5c 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -308,9 +308,20 @@ void TabView::SetActive(bool bActive) void TabView::SetAppActiveStatus(bool bAppActive) { MutexLock viewMapLock(m_viewsMutex); - for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + if( bAppActive ) + { + shared_ptr consoleView = this->GetActiveConsole(_T(__FUNCTION__)); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetAppActiveStatus(it->second == consoleView); + } + } + else { - it->second->SetAppActiveStatus(bAppActive); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetAppActiveStatus(false); + } } } @@ -331,9 +342,9 @@ void TabView::SplitHorizontally() HWND hwndConsoleView = CreateNewConsole(); if( hwndConsoleView ) { - multisplitClass::defaultFocusPane = multisplitClass::defaultFocusPane->split( + multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->split( hwndConsoleView, - CMultiSplitPane::HORIZONTAL); + CMultiSplitPane::HORIZONTAL)); } } } @@ -345,9 +356,9 @@ void TabView::SplitVertically() HWND hwndConsoleView = CreateNewConsole(); if( hwndConsoleView ) { - multisplitClass::defaultFocusPane = multisplitClass::defaultFocusPane->split( + multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->split( hwndConsoleView, - CMultiSplitPane::VERTICAL); + CMultiSplitPane::VERTICAL)); } } } diff --git a/Console/TabView.h b/Console/TabView.h index f000192d..35524c43 100644 --- a/Console/TabView.h +++ b/Console/TabView.h @@ -34,6 +34,11 @@ class TabView LRESULT OnEraseBackground (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/); LRESULT OnSize (UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL & bHandled); + virtual void OnPaneChanged(void) + { + SetAppActiveStatus(true); + } + shared_ptr GetActiveConsole(const TCHAR*); shared_ptr GetTabData() { return m_tabData; } diff --git a/wtl/wtl/include/multisplit.h b/wtl/wtl/include/multisplit.h index ab34db93..713efea4 100644 --- a/wtl/wtl/include/multisplit.h +++ b/wtl/wtl/include/multisplit.h @@ -855,13 +855,25 @@ public : POINT Point = { GET_X_LPARAM (Position), GET_Y_LPARAM (Position) }; pT->ScreenToClient (&Point); - this->defaultFocusPane = this->tree.getPane(Point); + SetDefaultFocusPane(this->tree.getPane(Point)); pT->SetFocus (); // focus child window ATLTRACE(_T("CMultiSplitImpl::OnMouseActivate: defaultFocusPane = %p\n"), this->defaultFocusPane); } return Result; } + void SetDefaultFocusPane(CMultiSplitPane* newDefaultPane) + { + bool boolNotify = newDefaultPane != this->defaultFocusPane; + this->defaultFocusPane = newDefaultPane; + if( boolNotify ) + this->OnPaneChanged(); + } + + virtual void OnPaneChanged(void) + { + } + LRESULT OnSettingChange (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/) { SystemSettingsGet (true); From 57f8b65fc956f1fec19b8055cacd2b5715a4e0fa Mon Sep 17 00:00:00 2001 From: cbucher Date: Mon, 15 Aug 2011 15:36:05 +0200 Subject: [PATCH 083/207] fix with split and remove, consoles inpacted are readjustded --- Console/TabView.cpp | 40 +++++++++++++++++- Console/TabView.h | 2 + wtl/wtl/include/multisplit.h | 81 +++++++++++++++++++++++------------- 3 files changed, 94 insertions(+), 29 deletions(-) diff --git a/Console/TabView.cpp b/Console/TabView.cpp index 49b28c5c..b3164fac 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -345,6 +345,16 @@ void TabView::SplitHorizontally() multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->split( hwndConsoleView, CMultiSplitPane::HORIZONTAL)); + + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->parent ) + { + WTL::CMultiSplitPane* splitted = multisplitClass::defaultFocusPane->parent; + HWND hwndPane0 = 0, hwndPane1 = 0; + if( splitted->pane0 ) hwndPane0 = splitted->pane0->window; + if( splitted->pane1 ) hwndPane1 = splitted->pane1->window; + + this->OnSplitBarMove(hwndPane0, hwndPane1, true); + } } } } @@ -359,6 +369,16 @@ void TabView::SplitVertically() multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->split( hwndConsoleView, CMultiSplitPane::VERTICAL)); + + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->parent ) + { + WTL::CMultiSplitPane* splitted = multisplitClass::defaultFocusPane->parent; + HWND hwndPane0 = 0, hwndPane1 = 0; + if( splitted->pane0 ) hwndPane0 = splitted->pane0->window; + if( splitted->pane1 ) hwndPane1 = splitted->pane1->window; + + this->OnSplitBarMove(hwndPane0, hwndPane1, true); + } } } } @@ -371,9 +391,27 @@ void TabView::CloseView() ConsoleViewMap::iterator iter = m_views.find(multisplitClass::defaultFocusPane->window); iter->second->DestroyWindow(); m_views.erase(iter); - multisplitClass::defaultFocusPane->remove(); + multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->remove()); if( m_views.size() == 0 ) m_mainFrame.CloseTab(this->m_hWnd); + else + { + if( multisplitClass::defaultFocusPane ) + { + this->OnSplitBarMove(multisplitClass::defaultFocusPane->window, 0, true); + } + } } +} + +void TabView::OnSplitBarMove(HWND hwndPane0, HWND hwndPane1, bool /*boolEnd*/) +{ + MutexLock viewMapLock(m_viewsMutex); + ConsoleViewMap::iterator iterPane0 = m_views.find(hwndPane0); + ConsoleViewMap::iterator iterPane1 = m_views.find(hwndPane1); + + CRect clientRect; + if( iterPane0 != m_views.end() ) iterPane0->second->AdjustRectAndResize(clientRect, WMSZ_BOTTOM); + if( iterPane1 != m_views.end() ) iterPane1->second->AdjustRectAndResize(clientRect, WMSZ_BOTTOM); } \ No newline at end of file diff --git a/Console/TabView.h b/Console/TabView.h index 35524c43..f822f0e2 100644 --- a/Console/TabView.h +++ b/Console/TabView.h @@ -39,6 +39,8 @@ class TabView SetAppActiveStatus(true); } + virtual void OnSplitBarMove(HWND hwndPane0, HWND hwndPane1, bool /*boolEnd*/); + shared_ptr GetActiveConsole(const TCHAR*); shared_ptr GetTabData() { return m_tabData; } diff --git a/wtl/wtl/include/multisplit.h b/wtl/wtl/include/multisplit.h index 713efea4..e7b264c5 100644 --- a/wtl/wtl/include/multisplit.h +++ b/wtl/wtl/include/multisplit.h @@ -232,12 +232,12 @@ namespace WTL return this->pane1; } - void remove(void) + CMultiSplitPane* remove(void) { if( this->isSplitBar() ) - return; + return 0; - if( parent ) + if( this->parent ) { CMultiSplitPane* survivor = this->window == this->parent->pane0->window? @@ -259,22 +259,27 @@ namespace WTL SWP_HIDEWINDOW); // parent = survivor - this->parent->window = survivor->window; - this->parent->splitType = survivor->splitType; - this->parent->splitRatio = survivor->splitRatio; - this->parent->pane0 = survivor->pane0; - this->parent->pane1 = survivor->pane1; - this->parent->splitType = NONE; + CMultiSplitPane* result = this->parent; + result->window = survivor->window; + result->splitType = survivor->splitType; + result->splitRatio = survivor->splitRatio; + result->pane0 = survivor->pane0; + result->pane1 = survivor->pane1; + result->splitType = NONE; // resize parent - this->parent->resize(this->parent->width, this->parent->height); + result->resize(result->width, result->height); // delete the two children of the parent delete target; survivor->pane0 = 0; survivor->pane1 = 0; delete survivor; + + return result; } + + return 0; } void resize(int width, int height) @@ -801,21 +806,37 @@ public : // end splitbar drag - LRESULT OnLButtonUp (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & bHandled) - { - if( this->resizingPane && !drawContentWhileResizing) - { - GhostBarDraw (); - T * pT = static_cast (this); - resizingPane->moveSplitBar(this->resizingDelta - this->resizingDelta0); - pT->InvalidateRect(NULL); - pT->UpdateWindow (); - } - this->resizingPane = 0; - ::ReleaseCapture (); - bHandled = FALSE; - return 1; - } + LRESULT OnLButtonUp (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & bHandled) + { + if( this->resizingPane ) + { + int delta = this->resizingDelta - this->resizingDelta0; + if( !drawContentWhileResizing ) + { + GhostBarDraw (); + T * pT = static_cast (this); + resizingPane->moveSplitBar(delta); + pT->InvalidateRect(NULL); + pT->UpdateWindow (); + } + + HWND hwndPane0 = 0, hwndPane1 = 0; + if( this->resizingPane->pane0 ) hwndPane0 = this->resizingPane->pane0->window; + if( this->resizingPane->pane1 ) hwndPane1 = this->resizingPane->pane1->window; + + this->resizingPane = 0; + ::ReleaseCapture (); + + if( delta ) + this->OnSplitBarMove(hwndPane0, hwndPane1, true); + } + bHandled = FALSE; + return 1; + } + + virtual void OnSplitBarMove(HWND /*hwndPane0*/, HWND /*hwndPane1*/, bool /*boolEnd*/) + { + } LRESULT OnSetFocus (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL & bHandled) { // give focus to defaultPane child @@ -855,9 +876,13 @@ public : POINT Point = { GET_X_LPARAM (Position), GET_Y_LPARAM (Position) }; pT->ScreenToClient (&Point); - SetDefaultFocusPane(this->tree.getPane(Point)); - pT->SetFocus (); // focus child window - ATLTRACE(_T("CMultiSplitImpl::OnMouseActivate: defaultFocusPane = %p\n"), this->defaultFocusPane); + CMultiSplitPane* pane = this->tree.getPane(Point); + if( pane && !pane->isSplitBar() ) + { + SetDefaultFocusPane(pane); + pT->SetFocus (); // focus child window + ATLTRACE(_T("CMultiSplitImpl::OnMouseActivate: defaultFocusPane = %p\n"), this->defaultFocusPane); + } } return Result; } From 9f4f465481a1ca0c239f4620e51d035384057a65 Mon Sep 17 00:00:00 2001 From: cbucher Date: Mon, 15 Aug 2011 18:35:39 +0200 Subject: [PATCH 084/207] fix offscreen bitmaps are not recreated when console columns and rows are not modified the bitmaps is created with a size of (column+1)*(rows+1) --- Console/ConsoleView.cpp | 38 +++++++++++++++++++++++++++----------- Console/ConsoleView.h | 1 + 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 17ed399f..9512f108 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -237,7 +237,7 @@ LRESULT ConsoleView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ if (m_bNeedFullRepaint) { - TRACE(L"ConsoleView::OnPaint\n"); + //TRACE(L"ConsoleView::OnPaint\n"); // we need to update offscreen buffers here for first paint and relative backgrounds RepaintText(m_dcText); UpdateOffscreen(dc.m_ps.rcPaint); @@ -269,11 +269,16 @@ LRESULT ConsoleView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ ////////////////////////////////////////////////////////////////////////////// - +long l1 = 0; LRESULT ConsoleView::OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { WINDOWPOS* pWinPos = reinterpret_cast(lParam); + if (!(pWinPos->flags & SWP_NOSIZE)) + { + TRACE(L"!!! ConsoleView::OnSize (%d) !!!\n", ::InterlockedIncrement(&l1)); + } + // showing the view, repaint if (pWinPos->flags & SWP_SHOWWINDOW) Repaint(false); @@ -965,8 +970,8 @@ void ConsoleView::GetRect(CRect& clientRect) clientRect.right = m_consoleHandler.GetConsoleParams()->dwColumns * m_nCharWidth + 2 * m_nVInsideBorder; clientRect.bottom = m_consoleHandler.GetConsoleParams()->dwRows * m_nCharHeight + 2 * m_nHInsideBorder; - if (m_bShowVScroll) clientRect.right += m_nVScrollWidth; - if (m_bShowHScroll) clientRect.bottom += m_nHScrollWidth; + if (m_bShowVScroll) clientRect.right += m_nVScrollWidth; + if (m_bShowHScroll) clientRect.bottom += m_nHScrollWidth; if( width > clientRect.right ) clientRect.right = width; if( height > clientRect.bottom ) clientRect.bottom = height; @@ -976,16 +981,27 @@ void ConsoleView::GetRect(CRect& clientRect) TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); } -////////////////////////////////////////////////////////////////////////////// +void ConsoleView::GetRectMax(CRect& clientMaxRect) +{ + clientMaxRect.left = 0; + clientMaxRect.top = 0; + clientMaxRect.right = (m_consoleHandler.GetConsoleParams()->dwColumns + 1) * m_nCharWidth + 2 * m_nVInsideBorder; + clientMaxRect.bottom = (m_consoleHandler.GetConsoleParams()->dwRows + 1) * m_nCharHeight + 2 * m_nHInsideBorder; + if (m_bShowVScroll) clientMaxRect.right += m_nVScrollWidth; + if (m_bShowHScroll) clientMaxRect.bottom += m_nHScrollWidth; +} ////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +long l2 = 0; void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge) { GetWindowRect(&clientRect); - TRACE(L"========AdjustRectAndResize=====================================\n"); + TRACE(L"========AdjustRectAndResize (%d)=================================\n", ::InterlockedIncrement(&l2)); TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); LONG width = clientRect.right - clientRect.left; @@ -1100,7 +1116,7 @@ void ConsoleView::RecreateOffscreenBuffers() void ConsoleView::Repaint(bool bFullRepaint) { - TRACE(L"ConsoleView::Repaint\n"); + //TRACE(L"ConsoleView::Repaint\n"); // OnPaint will do the work for a full repaint if (!m_bNeedFullRepaint) { @@ -1388,7 +1404,7 @@ void ConsoleView::CreateOffscreenBuffers() } // get window rect based on font and console size - GetRect(rectWindowMax); + GetRectMax(rectWindowMax); // create offscreen bitmaps if needed if (m_bmpOffscreen.IsNull()) CreateOffscreenBitmap(m_dcOffscreen, rectWindowMax, m_bmpOffscreen); @@ -1702,11 +1718,11 @@ void ConsoleView::RepaintText(CDC& dc) bitmapRect.top = 0; bitmapRect.right = bitmapSize.cx; bitmapRect.bottom = bitmapSize.cy; - +/* SIZE bitmapSize2; m_dcOffscreen.GetCurrentBitmap().GetSize(bitmapSize2); TRACE(L"ConsoleView::RepaintText (%ix%i on %ix%i)\n", bitmapSize.cx, bitmapSize.cy, bitmapSize2.cx, bitmapSize2.cy); - +*/ if (m_tabData->backgroundImageType == bktypeNone) { dc.FillRect(&bitmapRect, m_backgroundBrush); @@ -1883,7 +1899,7 @@ void ConsoleView::RepaintText(CDC& dc) void ConsoleView::RepaintTextChanges(CDC& dc) { - TRACE(L"ConsoleView::RepaintTextChanges\n"); + //TRACE(L"ConsoleView::RepaintTextChanges\n"); DWORD dwX = m_nVInsideBorder; DWORD dwY = m_nHInsideBorder; DWORD dwOffset = 0; diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index da816e00..a9c72a2e 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -99,6 +99,7 @@ class ConsoleView public: void GetRect(CRect& clientRect); + void GetRectMax(CRect& clientMaxRect); void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge); CPoint GetCellSize() { return CPoint(m_nCharWidth, m_nCharHeight); }; From 067d23f437aabced4e29dde02eafaf2f8c286284 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 20 Aug 2011 09:12:17 +0200 Subject: [PATCH 085/207] fix resize all consoles in a tab when a console change size --- Console/TabView.cpp | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/Console/TabView.cpp b/Console/TabView.cpp index b3164fac..9d8c68f2 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -346,15 +346,8 @@ void TabView::SplitHorizontally() hwndConsoleView, CMultiSplitPane::HORIZONTAL)); - if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->parent ) - { - WTL::CMultiSplitPane* splitted = multisplitClass::defaultFocusPane->parent; - HWND hwndPane0 = 0, hwndPane1 = 0; - if( splitted->pane0 ) hwndPane0 = splitted->pane0->window; - if( splitted->pane1 ) hwndPane1 = splitted->pane1->window; - - this->OnSplitBarMove(hwndPane0, hwndPane1, true); - } + CRect clientRect(0, 0, 0, 0); + AdjustRectAndResize(clientRect, WMSZ_BOTTOM); } } } @@ -370,15 +363,8 @@ void TabView::SplitVertically() hwndConsoleView, CMultiSplitPane::VERTICAL)); - if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->parent ) - { - WTL::CMultiSplitPane* splitted = multisplitClass::defaultFocusPane->parent; - HWND hwndPane0 = 0, hwndPane1 = 0; - if( splitted->pane0 ) hwndPane0 = splitted->pane0->window; - if( splitted->pane1 ) hwndPane1 = splitted->pane1->window; - - this->OnSplitBarMove(hwndPane0, hwndPane1, true); - } + CRect clientRect(0, 0, 0, 0); + AdjustRectAndResize(clientRect, WMSZ_BOTTOM); } } } @@ -397,21 +383,14 @@ void TabView::CloseView() m_mainFrame.CloseTab(this->m_hWnd); else { - if( multisplitClass::defaultFocusPane ) - { - this->OnSplitBarMove(multisplitClass::defaultFocusPane->window, 0, true); - } + CRect clientRect(0, 0, 0, 0); + AdjustRectAndResize(clientRect, WMSZ_BOTTOM); } } } -void TabView::OnSplitBarMove(HWND hwndPane0, HWND hwndPane1, bool /*boolEnd*/) +void TabView::OnSplitBarMove(HWND /*hwndPane0*/, HWND /*hwndPane1*/, bool /*boolEnd*/) { - MutexLock viewMapLock(m_viewsMutex); - ConsoleViewMap::iterator iterPane0 = m_views.find(hwndPane0); - ConsoleViewMap::iterator iterPane1 = m_views.find(hwndPane1); - - CRect clientRect; - if( iterPane0 != m_views.end() ) iterPane0->second->AdjustRectAndResize(clientRect, WMSZ_BOTTOM); - if( iterPane1 != m_views.end() ) iterPane1->second->AdjustRectAndResize(clientRect, WMSZ_BOTTOM); + CRect clientRect(0, 0, 0, 0); + AdjustRectAndResize(clientRect, WMSZ_BOTTOM); } \ No newline at end of file From 4b48e3722519f35af2c3190f27938549f5aebdcc Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 20 Aug 2011 15:32:59 +0200 Subject: [PATCH 086/207] fix focus and foreground window --- Console/MainFrame.cpp | 3 +++ wtl/wtl/include/multisplit.h | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index e928aaf9..dabc3dbb 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1217,6 +1217,7 @@ LRESULT MainFrame::OnCloseView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCt { if( m_activeTabView ) m_activeTabView->CloseView(); + ::SetForegroundWindow(m_hWnd); return 0; } @@ -1229,6 +1230,7 @@ LRESULT MainFrame::OnSplitHorizontally(WORD /*wNotifyCode*/, WORD /*wID*/, HWND { if( m_activeTabView ) m_activeTabView->SplitHorizontally(); + ::SetForegroundWindow(m_hWnd); return 0; } @@ -1241,6 +1243,7 @@ LRESULT MainFrame::OnSplitVertically(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /* { if( m_activeTabView ) m_activeTabView->SplitVertically(); + ::SetForegroundWindow(m_hWnd); return 0; } diff --git a/wtl/wtl/include/multisplit.h b/wtl/wtl/include/multisplit.h index e7b264c5..e2938d50 100644 --- a/wtl/wtl/include/multisplit.h +++ b/wtl/wtl/include/multisplit.h @@ -880,7 +880,7 @@ public : if( pane && !pane->isSplitBar() ) { SetDefaultFocusPane(pane); - pT->SetFocus (); // focus child window + //pT->SetFocus (); // focus child window ATLTRACE(_T("CMultiSplitImpl::OnMouseActivate: defaultFocusPane = %p\n"), this->defaultFocusPane); } } @@ -891,6 +891,8 @@ public : { bool boolNotify = newDefaultPane != this->defaultFocusPane; this->defaultFocusPane = newDefaultPane; + if( newDefaultPane && ::IsWindow(newDefaultPane->window) ) + ::SetFocus(newDefaultPane->window); if( boolNotify ) this->OnPaneChanged(); } From fcba211060f341837742ee8cdf3e70401314080e Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 20 Aug 2011 19:24:25 +0200 Subject: [PATCH 087/207] add grouping feature --- Console/ConsoleView.cpp | 11 +++++-- Console/ConsoleView.h | 4 +++ Console/MainFrame.cpp | 67 ++++++++++++++++++++++++++++++----------- Console/MainFrame.h | 2 ++ Console/TabView.cpp | 42 ++++++++++++++++++++++++++ Console/TabView.h | 8 ++++- 6 files changed, 112 insertions(+), 22 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 9512f108..bbb23bac 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -66,6 +66,7 @@ ConsoleView::ConsoleView(MainFrame& mainFrame, HWND hwndTabView, shared_ptrhwndConsoleWindow, uMsg, wParam, lParam); + //TRACE(L"Msg: 0x%04X, wParam: 0x%08X, lParam: 0x%08X\n", uMsg, wParam, lParam); + if( this->IsGrouped() ) + m_mainFrame.PostMessageToConsoles(uMsg, wParam, lParam); + else + ::PostMessage(m_consoleHandler.GetConsoleParams()->hwndConsoleWindow, uMsg, wParam, lParam); } return 0; @@ -554,7 +558,8 @@ LRESULT ConsoleView::OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL case MouseSettings::cmdPaste : { - Paste(); + //Paste(); + m_mainFrame.PasteToConsoles(); break; } diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index a9c72a2e..b4dbb556 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -136,6 +136,9 @@ class ConsoleView const CString& GetExceptionMessage() const { return m_exceptionMessage; } + inline bool IsGrouped() const { return m_boolIsGrouped; } + void Group(bool b) { m_boolIsGrouped = b; } + private: void OnConsoleChange(bool bResize); @@ -181,6 +184,7 @@ class ConsoleView bool m_bNeedFullRepaint; bool m_bUseTextAlphaBlend; bool m_bConsoleWindowVisible; + bool m_boolIsGrouped; DWORD m_dwStartupRows; DWORD m_dwStartupColumns; diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index dabc3dbb..bdea8ef7 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1254,7 +1254,11 @@ LRESULT MainFrame::OnSplitVertically(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /* LRESULT MainFrame::OngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - MessageBox(_T(__FUNCTION__)); + MutexLock lock(m_tabsMutex); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) + { + it->second->Group(true); + } return 0; } @@ -1265,7 +1269,11 @@ LRESULT MainFrame::OngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnUngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - MessageBox(_T(__FUNCTION__)); + MutexLock lock(m_tabsMutex); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) + { + it->second->Group(false); + } return 0; } @@ -1276,7 +1284,8 @@ LRESULT MainFrame::OnUngroupAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndC LRESULT MainFrame::OnGroupTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - MessageBox(_T(__FUNCTION__)); + if (!m_activeTabView) return 0; + m_activeTabView->Group(true); return 0; } @@ -1287,7 +1296,8 @@ LRESULT MainFrame::OnGroupTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnUngroupTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - MessageBox(_T(__FUNCTION__)); + if (!m_activeTabView) return 0; + m_activeTabView->Group(false); return 0; } @@ -1309,13 +1319,7 @@ LRESULT MainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeTabView) return 0; - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); - if( activeConsoleView ) - { - activeConsoleView->Paste(); - } - + PasteToConsoles(); return 0; } @@ -1360,13 +1364,7 @@ LRESULT MainFrame::OnEditClearSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND LRESULT MainFrame::OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - if (!m_activeTabView) return 0; - shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); - if( activeConsoleView ) - { - activeConsoleView->Paste(); - } - + PasteToConsoles(); return 0; } @@ -2464,3 +2462,36 @@ BOOL MainFrame::SetTrayIcon(DWORD dwMessage) { ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +void MainFrame::PostMessageToConsoles(UINT Msg, WPARAM wParam, LPARAM lParam) +{ + MutexLock lock(m_tabsMutex); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) + { + it->second->PostMessageToConsoles(Msg, wParam, lParam); + } +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +void MainFrame::PasteToConsoles() +{ + if (!m_activeTabView) return; + shared_ptr activeConsoleView = m_activeTabView->GetActiveConsole(_T(__FUNCTION__)); + if( activeConsoleView ) + { + if( activeConsoleView->IsGrouped() ) + { + MutexLock lock(m_tabsMutex); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) + { + it->second->PasteToConsoles(); + } + } + else + activeConsoleView->Paste(); + } +} \ No newline at end of file diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 5397d1a1..99a80f90 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -213,6 +213,8 @@ class MainFrame void AdjustWindowSize(bool bResizeConsole); void RecreateOffscreenBuffers(); void CloseTab(HWND hwndTabView); + void PostMessageToConsoles(UINT Msg, WPARAM wParam, LPARAM lParam); + void PasteToConsoles(); private: diff --git a/Console/TabView.cpp b/Console/TabView.cpp index 9d8c68f2..a3d481a7 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -19,6 +19,7 @@ TabView::TabView(MainFrame& mainFrame, shared_ptr tabData) ,m_strTitle(tabData->strTitle.c_str()) ,m_bigIcon() ,m_smallIcon() +,m_boolIsGrouped(false) { } @@ -135,6 +136,7 @@ HWND TabView::CreateNewConsole(void) } #endif shared_ptr consoleView(new ConsoleView(m_mainFrame, m_hWnd, m_tabData, m_strTitle, dwRows, dwColumns)); + consoleView->Group(this->IsGrouped()); UserCredentials userCredentials; if (m_tabData->bRunAsUser) @@ -393,4 +395,44 @@ void TabView::OnSplitBarMove(HWND /*hwndPane0*/, HWND /*hwndPane1*/, bool /*bool { CRect clientRect(0, 0, 0, 0); AdjustRectAndResize(clientRect, WMSZ_BOTTOM); +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +void TabView::PostMessageToConsoles(UINT Msg, WPARAM wParam, LPARAM lParam) +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + ::PostMessage(it->second->GetConsoleHandler().GetConsoleParams()->hwndConsoleWindow, Msg, wParam, lParam); + } +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +void TabView::PasteToConsoles() +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->Paste(); + } +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +void TabView::Group(bool b) +{ + MutexLock viewMapLock(m_viewsMutex); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->Group(b); + } + m_boolIsGrouped = b; } \ No newline at end of file diff --git a/Console/TabView.h b/Console/TabView.h index f822f0e2..c85c408e 100644 --- a/Console/TabView.h +++ b/Console/TabView.h @@ -61,6 +61,12 @@ class TabView void SplitVertically(); void CloseView(); + void PostMessageToConsoles(UINT Msg, WPARAM wParam, LPARAM lParam); + void PasteToConsoles(); + + inline bool IsGrouped() const { return m_boolIsGrouped; } + void Group(bool b); + private: HWND CreateNewConsole(void); @@ -72,7 +78,7 @@ class TabView CString m_strTitle; CIcon m_bigIcon; CIcon m_smallIcon; - + bool m_boolIsGrouped; // static members private: From d135cfa49e09cb071233178e4f5ee2b6a3292f02 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 21 Aug 2011 08:26:14 +0200 Subject: [PATCH 088/207] add next view / prev view --- Console/MainFrame.cpp | 6 ++++-- Console/TabView.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++ Console/TabView.h | 2 ++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index bdea8ef7..fdce17b1 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1193,7 +1193,8 @@ LRESULT MainFrame::OnPrevTab(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl* LRESULT MainFrame::OnNextView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - MessageBox(_T(__FUNCTION__)); + if( m_activeTabView ) + m_activeTabView->NextView(); return 0; } @@ -1204,7 +1205,8 @@ LRESULT MainFrame::OnNextView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl LRESULT MainFrame::OnPrevView(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { - MessageBox(_T(__FUNCTION__)); + if( m_activeTabView ) + m_activeTabView->PrevView(); return 0; } diff --git a/Console/TabView.cpp b/Console/TabView.cpp index a3d481a7..a6a1a458 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -337,6 +337,10 @@ void TabView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge) this->GetRect(clientRect); } +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + void TabView::SplitHorizontally() { if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) @@ -371,6 +375,10 @@ void TabView::SplitVertically() } } +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + void TabView::CloseView() { if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) @@ -391,6 +399,46 @@ void TabView::CloseView() } } +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + +void TabView::NextView() +{ + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) + { + MutexLock viewMapLock(m_viewsMutex); + if( m_views.size() > 1 ) + { + ConsoleViewMap::iterator iter = m_views.find(multisplitClass::defaultFocusPane->window); + ++iter; + if( iter == m_views.end() ) + iter = m_views.begin(); + multisplitClass::SetDefaultFocusPane(multisplitClass::tree.get(iter->first)); + } + } +} + +void TabView::PrevView() +{ + if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) + { + MutexLock viewMapLock(m_viewsMutex); + if( m_views.size() > 1 ) + { + ConsoleViewMap::iterator iter = m_views.find(multisplitClass::defaultFocusPane->window); + if( iter == m_views.begin() ) + iter = m_views.end(); + --iter; + multisplitClass::SetDefaultFocusPane(multisplitClass::tree.get(iter->first)); + } + } +} + +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// + void TabView::OnSplitBarMove(HWND /*hwndPane0*/, HWND /*hwndPane1*/, bool /*boolEnd*/) { CRect clientRect(0, 0, 0, 0); diff --git a/Console/TabView.h b/Console/TabView.h index c85c408e..507aa3ad 100644 --- a/Console/TabView.h +++ b/Console/TabView.h @@ -60,6 +60,8 @@ class TabView void SplitHorizontally(); void SplitVertically(); void CloseView(); + void NextView(); + void PrevView(); void PostMessageToConsoles(UINT Msg, WPARAM wParam, LPARAM lParam); void PasteToConsoles(); From bf4a3809c9b8c4a8191d97751a9ea065ba9e6753 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 21 Aug 2011 08:46:31 +0200 Subject: [PATCH 089/207] fix remove red background (it was for testing) fix reformat code --- wtl/wtl/include/multisplit.h | 206 ++++++++++++++++++----------------- 1 file changed, 105 insertions(+), 101 deletions(-) diff --git a/wtl/wtl/include/multisplit.h b/wtl/wtl/include/multisplit.h index e2938d50..ad6a0bf0 100644 --- a/wtl/wtl/include/multisplit.h +++ b/wtl/wtl/include/multisplit.h @@ -633,10 +633,11 @@ public : // draw all splitter bars & empty panes, occupied panes draw themselves - void Draw (CDCHandle dc) - { - ATLASSERT(!(dc.m_hDC == 0)); + void Draw (CDCHandle dc) + { + ATLASSERT(!(dc.m_hDC == 0)); +#if 0 CPen penYellow; penYellow.CreatePen(PS_SOLID, 1, RGB(255, 255, 0)); dc.SelectPen(penYellow); @@ -651,13 +652,14 @@ public : dc.LineTo(visibleRect.right - 1 - marge, visibleRect.bottom - 1 - marge); dc.MoveTo(visibleRect.right - 1 - marge, visibleRect.top + marge); dc.LineTo(visibleRect.left + marge, visibleRect.bottom - 1 - marge); +#endif - ATLTRACE(_T("CMultiSplitImpl::Draw: %d %d %d %d (%d %d)\n"), - visibleRect.left, visibleRect.top, visibleRect.right, visibleRect.bottom, - visibleRect.Width (), visibleRect.Height ()); + ATLTRACE(_T("CMultiSplitImpl::Draw: %d %d %d %d (%d %d)\n"), + visibleRect.left, visibleRect.top, visibleRect.right, visibleRect.bottom, + visibleRect.Width (), visibleRect.Height ()); this->tree.draw(dc); - } + } // Overrideable by derived classes @@ -690,28 +692,25 @@ public : // Message map and handlers - typedef CMultiSplitImpl< T> thisClass; - BEGIN_MSG_MAP (thisClass) - MESSAGE_HANDLER (WM_CREATE, OnCreate) - MESSAGE_HANDLER (WM_PAINT, OnPaint) -// MESSAGE_HANDLER (WM_PRINTCLIENT, OnPaint) -// if (IsInteractive ()) - { - MESSAGE_HANDLER (WM_SETCURSOR, OnSetCursor) // cursor in client area - MESSAGE_HANDLER (WM_MOUSEMOVE, OnMouseMove) - MESSAGE_HANDLER (WM_LBUTTONDOWN, OnLButtonDown) - MESSAGE_HANDLER (WM_LBUTTONUP, OnLButtonUp) + typedef CMultiSplitImpl< T> thisClass; + BEGIN_MSG_MAP (thisClass) + MESSAGE_HANDLER (WM_CREATE, OnCreate) + MESSAGE_HANDLER (WM_PAINT, OnPaint) + //MESSAGE_HANDLER (WM_PRINTCLIENT, OnPaint) + MESSAGE_HANDLER (WM_SETCURSOR, OnSetCursor) // cursor in client area + MESSAGE_HANDLER (WM_MOUSEMOVE, OnMouseMove) + MESSAGE_HANDLER (WM_LBUTTONDOWN, OnLButtonDown) + MESSAGE_HANDLER (WM_LBUTTONUP, OnLButtonUp) #if 0 - MESSAGE_HANDLER (WM_VSCROLL, OnScroll) // scroll bar messages - MESSAGE_HANDLER (WM_HSCROLL, OnScroll) - MESSAGE_HANDLER (WM_MOUSEWHEEL, OnMouseWheel) - MESSAGE_HANDLER (WM_LBUTTONDBLCLK, OnLButtonDoubleClick) + MESSAGE_HANDLER (WM_VSCROLL, OnScroll) // scroll bar messages + MESSAGE_HANDLER (WM_HSCROLL, OnScroll) + MESSAGE_HANDLER (WM_MOUSEWHEEL, OnMouseWheel) + MESSAGE_HANDLER (WM_LBUTTONDBLCLK, OnLButtonDoubleClick) #endif - } - MESSAGE_HANDLER (WM_SETFOCUS, OnSetFocus) - MESSAGE_HANDLER (WM_MOUSEACTIVATE, OnMouseActivate) - MESSAGE_HANDLER (WM_SETTINGCHANGE, OnSettingChange) - END_MSG_MAP () + MESSAGE_HANDLER (WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER (WM_MOUSEACTIVATE, OnMouseActivate) + MESSAGE_HANDLER (WM_SETTINGCHANGE, OnSettingChange) + END_MSG_MAP () LRESULT OnCreate (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL & bHandled) { @@ -732,58 +731,60 @@ public : return 0; } - LRESULT OnSetCursor (UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & bHandled) - { - T * pT = static_cast (this); - if (reinterpret_cast(wParam) == pT->m_hWnd && LOWORD (lParam) == HTCLIENT) - { - DWORD Position = ::GetMessagePos (); - POINT Point = { GET_X_LPARAM (Position), GET_Y_LPARAM (Position) }; - pT->ScreenToClient (&Point); + LRESULT OnSetCursor (UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & bHandled) + { + T * pT = static_cast (this); + if (reinterpret_cast(wParam) == pT->m_hWnd && LOWORD (lParam) == HTCLIENT) + { + DWORD Position = ::GetMessagePos (); + POINT Point = { GET_X_LPARAM (Position), GET_Y_LPARAM (Position) }; + pT->ScreenToClient (&Point); if ( this->tree.getSplitBar(Point) ) - return 1; - } - bHandled = FALSE; - return 0; - } + return 1; + } + bHandled = FALSE; + return 0; + } // Dragging splitbar resizes panes to either side of bar // Pane size is checked and changed on every receipt of this message. - LRESULT OnMouseMove (UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & bHandled) - { - T * pT = static_cast (this); - POINT Point = { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) }; - if ((wParam & MK_LBUTTON) && ::GetCapture () == pT->m_hWnd) - { // resizing + LRESULT OnMouseMove (UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & bHandled) + { + T * pT = static_cast (this); + POINT Point = { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) }; + if ((wParam & MK_LBUTTON) && ::GetCapture () == pT->m_hWnd) + { + // resizing int delta = resizingPane->getSplitBarDelta(Point); - if ( delta ) - { - if (drawContentWhileResizing) - { + if ( delta ) + { + if (drawContentWhileResizing) + { resizingPane->moveSplitBar(delta - this->resizingDelta0); pT->InvalidateRect(NULL); - pT->UpdateWindow (); - } - else - { - GhostBarDraw (); + pT->UpdateWindow (); + } + else + { + GhostBarDraw (); this->resizingDelta = delta; GhostBarDraw (); - } - } - } - else - { // not dragging, just set cursor + } + } + } + else + { + // not dragging, just set cursor CMultiSplitPane* splitBar = this->tree.getSplitBar(Point); - if ( splitBar ) + if ( splitBar ) ::SetCursor (splitBar->splitType == CMultiSplitPane::VERTICAL ? vertCursor : horzCursor); - bHandled = FALSE; - } - return 0; - } + bHandled = FALSE; + } + return 0; + } // start splitbar drag @@ -838,43 +839,46 @@ public : { } - LRESULT OnSetFocus (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL & bHandled) - { // give focus to defaultPane child -// ATLTRACE(_T("CMultiSplitImpl::OnSetFocus: %p\n"), defaultFocusPane); + LRESULT OnSetFocus (UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL & bHandled) + { + // give focus to defaultPane child + //ATLTRACE(_T("CMultiSplitImpl::OnSetFocus: %p\n"), defaultFocusPane); if( defaultFocusPane && defaultFocusPane->window ) - ::SetFocus(defaultFocusPane->window); + ::SetFocus(defaultFocusPane->window); - bHandled = FALSE; - return 1; - } + bHandled = FALSE; + return 1; + } - LRESULT OnMouseActivate (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & /*bHandled*/) - { - T * pT = static_cast (this); - LRESULT Result = pT->DefWindowProc (uMsg, wParam, lParam); -/* LPCTSTR Text; - switch (Result) - { - case MA_ACTIVATE : - Text = _T("MA_ACTIVATE"); - break; - case MA_ACTIVATEANDEAT : - Text = _T("MA_ACTIVATEANDEAT"); - break; - case MA_NOACTIVATE : - Text = _T("MA_NOACTIVATE"); - break; - case MA_NOACTIVATEANDEAT : - Text = _T("MA_NOACTIVATEANDEAT"); - break; - } - ATLTRACE(_T("CMultiSplitImpl::OnMouseActivate: %s\n"), Text); -*/ + LRESULT OnMouseActivate (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & /*bHandled*/) + { + T * pT = static_cast (this); + LRESULT Result = pT->DefWindowProc (uMsg, wParam, lParam); + /* + LPCTSTR Text; + switch (Result) + { + case MA_ACTIVATE : + Text = _T("MA_ACTIVATE"); + break; + case MA_ACTIVATEANDEAT : + Text = _T("MA_ACTIVATEANDEAT"); + break; + case MA_NOACTIVATE : + Text = _T("MA_NOACTIVATE"); + break; + case MA_NOACTIVATEANDEAT : + Text = _T("MA_NOACTIVATEANDEAT"); + break; + } + ATLTRACE(_T("CMultiSplitImpl::OnMouseActivate: %s\n"), Text); + */ if (Result == MA_ACTIVATE || Result == MA_ACTIVATEANDEAT) - { // select focus pane from mouse position - DWORD Position = ::GetMessagePos (); - POINT Point = { GET_X_LPARAM (Position), GET_Y_LPARAM (Position) }; - pT->ScreenToClient (&Point); + { + // select focus pane from mouse position + DWORD Position = ::GetMessagePos (); + POINT Point = { GET_X_LPARAM (Position), GET_Y_LPARAM (Position) }; + pT->ScreenToClient (&Point); CMultiSplitPane* pane = this->tree.getPane(Point); if( pane && !pane->isSplitBar() ) @@ -883,9 +887,9 @@ public : //pT->SetFocus (); // focus child window ATLTRACE(_T("CMultiSplitImpl::OnMouseActivate: defaultFocusPane = %p\n"), this->defaultFocusPane); } - } - return Result; - } + } + return Result; + } void SetDefaultFocusPane(CMultiSplitPane* newDefaultPane) { From abc712606aca3a4093a9ad33a5923078b186706b Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 21 Aug 2011 09:14:02 +0200 Subject: [PATCH 090/207] fix console ending does not longer close all the tab --- Console/ConsoleView.cpp | 2 +- Console/MainFrame.cpp | 9 +++++++-- Console/TabView.cpp | 37 +++++++++++++++++++++++++------------ Console/TabView.h | 2 +- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index bbb23bac..d8943619 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -1367,7 +1367,7 @@ void ConsoleView::OnConsoleChange(bool bResize) void ConsoleView::OnConsoleClose() { - if (::IsWindow(m_hWnd)) m_mainFrame.PostMessage(UM_CONSOLE_CLOSED, reinterpret_cast(m_hwndTabView), 0); + if (::IsWindow(m_hWnd)) m_mainFrame.PostMessage(UM_CONSOLE_CLOSED, reinterpret_cast(m_hWnd), 0); } ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index fdce17b1..e6f4147e 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -803,8 +803,13 @@ LRESULT MainFrame::OnConsoleResized(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*l LRESULT MainFrame::OnConsoleClosed(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /* bHandled */) { - CloseTab(reinterpret_cast(wParam)); - return 0; + MutexLock lock(m_tabsMutex); + for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) + { + if( it->second->CloseView(reinterpret_cast(wParam)) ) + break; + } + return 0; } ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/TabView.cpp b/Console/TabView.cpp index a6a1a458..2fdf8957 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -379,24 +379,37 @@ void TabView::SplitVertically() ///////////////////////////////////////////////////////////////////////////// -void TabView::CloseView() +bool TabView::CloseView(HWND hwnd /*= 0*/) { - if( multisplitClass::defaultFocusPane && multisplitClass::defaultFocusPane->window ) + if( hwnd == 0 ) { - MutexLock viewMapLock(m_viewsMutex); - ConsoleViewMap::iterator iter = m_views.find(multisplitClass::defaultFocusPane->window); - iter->second->DestroyWindow(); - m_views.erase(iter); - multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->remove()); + if( multisplitClass::defaultFocusPane ) + hwnd = multisplitClass::defaultFocusPane->window; + } - if( m_views.size() == 0 ) - m_mainFrame.CloseTab(this->m_hWnd); - else + if( hwnd ) + { + MutexLock viewMapLock(m_viewsMutex); + ConsoleViewMap::iterator iter = m_views.find(hwnd); + if( iter != m_views.end() ) { - CRect clientRect(0, 0, 0, 0); - AdjustRectAndResize(clientRect, WMSZ_BOTTOM); + iter->second->DestroyWindow(); + m_views.erase(iter); + multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->remove()); + + if( m_views.size() == 0 ) + m_mainFrame.CloseTab(this->m_hWnd); + else + { + CRect clientRect(0, 0, 0, 0); + AdjustRectAndResize(clientRect, WMSZ_BOTTOM); + } + + return true; } } + + return false; } ///////////////////////////////////////////////////////////////////////////// diff --git a/Console/TabView.h b/Console/TabView.h index 507aa3ad..10f849b8 100644 --- a/Console/TabView.h +++ b/Console/TabView.h @@ -59,7 +59,7 @@ class TabView void SplitHorizontally(); void SplitVertically(); - void CloseView(); + bool CloseView(HWND hwnd = 0); void NextView(); void PrevView(); From 531c763a01cc1bf2432f80fbc7c00fe356f436a4 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 21 Aug 2011 19:16:49 +0200 Subject: [PATCH 091/207] fix new tab are adjusted (to match with a resized mainframe) --- Console/MainFrame.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index e6f4147e..79d2d389 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1659,6 +1659,8 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir if (m_tabs.size() > 1) { + CRect clientRect(0, 0, 0, 0); + tabView->AdjustRectAndResize(clientRect, WMSZ_BOTTOM); UIEnable(ID_FILE_CLOSE_TAB, TRUE); } if ( g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowTabs && From 2a9241ae08d2ffa0cb8cad28ed1767b70f77bfe3 Mon Sep 17 00:00:00 2001 From: cbucher Date: Mon, 22 Aug 2011 12:00:22 +0200 Subject: [PATCH 092/207] fix focus not detected with quake like mode --- Console/MainFrame.cpp | 9 +++++---- Console/MainFrame.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 79d2d389..747f1300 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -51,6 +51,7 @@ MainFrame::MainFrame , m_bRestoringWindow(false) , m_rectRestoredWnd(0, 0, 0, 0) , m_iSelectionSize(0) +, m_bAppActive(true) { m_Margins.cxLeftWidth = 0; m_Margins.cxRightWidth = 0; @@ -373,18 +374,18 @@ LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, LRESULT MainFrame::OnActivateApp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { - BOOL bActivating = static_cast(wParam); + m_bAppActive = static_cast(wParam)? true : false; if (!m_activeTabView) return 0; - m_activeTabView->SetAppActiveStatus(bActivating ? true : false); + m_activeTabView->SetAppActiveStatus(m_bAppActive); TransparencySettings& transparencySettings = g_settingsHandler->GetAppearanceSettings().transparencySettings; if ((transparencySettings.transType == transAlpha) && ((transparencySettings.byActiveAlpha != 255) || (transparencySettings.byInactiveAlpha != 255))) { - if (bActivating) + if (m_bAppActive) { ::SetLayeredWindowAttributes(m_hWnd, RGB(0, 0, 0), transparencySettings.byActiveAlpha, LWA_ALPHA); } @@ -426,7 +427,7 @@ LRESULT MainFrame::OnHotKey(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOO { ::AnimateWindow(m_hWnd, 300, AW_ACTIVATE | AW_SLIDE | AW_VER_POSITIVE); } - else if(this->GetActiveView() == GetFocus()) + else if(m_bAppActive) { ::AnimateWindow(m_hWnd, 300, AW_HIDE | AW_SLIDE | AW_VER_NEGATIVE); bActivate = false; diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 99a80f90..7bf45649 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -282,6 +282,7 @@ class MainFrame DWORD m_dwWindowHeight; DWORD m_dwResizeWindowEdge; + bool m_bAppActive; bool m_bRestoringWindow; CRect m_rectRestoredWnd; From 04985266cab361da820f48aeea8805fa2a09da71 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 28 Aug 2011 13:57:14 +0200 Subject: [PATCH 093/207] ConsoleView::AdjustRectAndResize called by MainFrame::AdjustWindowSize(true): RecreateOffscreenBuffers Repaint(true) fix offscreen buffers not recreated when row x col size is not changed todo no offscreen buffers recreation is needed with only font resizing --- Console/ConsoleView.cpp | 12 ++++++------ Console/MainFrame.cpp | 14 +------------- Console/MainFrame.h | 1 - Console/TabView.cpp | 9 --------- Console/TabView.h | 1 - 5 files changed, 7 insertions(+), 30 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index d8943619..15ae7f65 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -331,9 +331,7 @@ LRESULT ConsoleView::OnConsoleFwdMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BO m_appearanceSettings.fontSettings.dwSize = size; // recreate font with new size RecreateFont(); - m_mainFrame.AdjustWindowSize(false); - m_mainFrame.RecreateOffscreenBuffers(); - Repaint(true); + m_mainFrame.AdjustWindowSize(true); } return 0; @@ -804,8 +802,6 @@ LRESULT ConsoleView::OnUpdateConsoleView(UINT /*uMsg*/, WPARAM wParam, LPARAM /* */ InitializeScrollbars(); - RecreateOffscreenBuffers(); - // notify parent about resize m_mainFrame.SendMessage(UM_CONSOLE_RESIZED, 0, 0); } @@ -1057,6 +1053,9 @@ void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdg TRACE(L"console view: 0x%08X, adjusted: %ix%i\n", m_hWnd, dwRows, dwColumns); TRACE(L"================================================================\n"); + RecreateOffscreenBuffers(); + Repaint(true); + m_consoleHandler.GetNewConsoleSize().SetReqEvent(); } @@ -1324,6 +1323,7 @@ void ConsoleView::DumpBuffer() void ConsoleView::OnConsoleChange(bool bResize) { + TRACE(L" !!!!!!!!!!!!!!! ConsoleView::OnConsoleChange(%s) !!!!!!!!!!!!!!!!", bResize?L"true":L"false"); SharedMemory& consoleParams = m_consoleHandler.GetConsoleParams(); SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); SharedMemory& consoleBuffer = m_consoleHandler.GetConsoleBuffer(); @@ -1409,7 +1409,7 @@ void ConsoleView::CreateOffscreenBuffers() } // get window rect based on font and console size - GetRectMax(rectWindowMax); + GetRect(rectWindowMax); // create offscreen bitmaps if needed if (m_bmpOffscreen.IsNull()) CreateOffscreenBitmap(m_dcOffscreen, rectWindowMax, m_bmpOffscreen); diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 747f1300..dc66257e 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1477,9 +1477,7 @@ LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn } ConsoleView::RecreateFont(); - AdjustWindowSize(false); - RecreateOffscreenBuffers(); - m_activeTabView->Repaint(true); + AdjustWindowSize(true); } RegisterGlobalHotkeys(); @@ -2201,16 +2199,6 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole) SetMargins(); } -void MainFrame::RecreateOffscreenBuffers() -{ - MutexLock viewMapLock(m_tabsMutex); - - for (TabViewMap::iterator it = m_tabs.begin(); it != m_tabs.end(); ++it) - { - it->second->RecreateOffscreenBuffers(); - } -} - ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 7bf45649..30ff77f3 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -211,7 +211,6 @@ class MainFrame void AdjustWindowRect(CRect& rect); void SetSelectionSize(int iSelectionSize); void AdjustWindowSize(bool bResizeConsole); - void RecreateOffscreenBuffers(); void CloseTab(HWND hwndTabView); void PostMessageToConsoles(UINT Msg, WPARAM wParam, LPARAM lParam); void PasteToConsoles(); diff --git a/Console/TabView.cpp b/Console/TabView.cpp index 2fdf8957..76e9ce81 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -278,15 +278,6 @@ void TabView::MainframeMoving() } } -void TabView::RecreateOffscreenBuffers() -{ - MutexLock viewMapLock(m_viewsMutex); - for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) - { - it->second->RecreateOffscreenBuffers(); - } -} - void TabView::SetTitle(const CString& strTitle) { m_strTitle = strTitle; diff --git a/Console/TabView.h b/Console/TabView.h index 10f849b8..93984375 100644 --- a/Console/TabView.h +++ b/Console/TabView.h @@ -53,7 +53,6 @@ class TabView void MainframeMoving(); void Repaint(bool bFullRepaint); void InitializeScrollbars(); - void RecreateOffscreenBuffers(); void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge); void GetRect(CRect& clientRect); From 8111b4530f1935e69222d85571a11f77c6ebbab7 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 28 Aug 2011 13:57:36 +0200 Subject: [PATCH 094/207] fix debug ASSERT --- Console/DlgSettingsTabs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Console/DlgSettingsTabs.cpp b/Console/DlgSettingsTabs.cpp index 0be2d762..4f0c0b73 100644 --- a/Console/DlgSettingsTabs.cpp +++ b/Console/DlgSettingsTabs.cpp @@ -42,7 +42,7 @@ LRESULT DlgSettingsTabs::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM / m_listCtrl.InsertColumn(0, L"Tab name"); m_listCtrl.SetColumnWidth(0, 188); m_listCtrl.SetImageList(m_ImageList, LVSIL_SMALL); - m_listCtrl.SetIconSpacing(16, 16); + //m_listCtrl.SetIconSpacing(16, 16); TabDataVector::iterator it = m_tabSettings.tabDataVector.begin(); for (; it != m_tabSettings.tabDataVector.end(); ++it) From 6707b0460fa7f3ce823f4b464e72e3460d27cf04 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 28 Aug 2011 18:22:42 +0200 Subject: [PATCH 095/207] no offscreen buffers recreation is needed with only font resizing --- Console/ConsoleView.cpp | 21 ++++++++++++--------- Console/ConsoleView.h | 4 ++-- Console/MainFrame.cpp | 33 ++++++++++++++------------------- Console/MainFrame.h | 2 +- Console/TabView.cpp | 12 ++++++------ Console/TabView.h | 2 +- Console/stdafx.h | 9 +++++++++ 7 files changed, 45 insertions(+), 38 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 15ae7f65..238b048a 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -331,7 +331,7 @@ LRESULT ConsoleView::OnConsoleFwdMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BO m_appearanceSettings.fontSettings.dwSize = size; // recreate font with new size RecreateFont(); - m_mainFrame.AdjustWindowSize(true); + m_mainFrame.AdjustWindowSize(ADJUSTSIZE_FONT); } return 0; @@ -998,7 +998,7 @@ void ConsoleView::GetRectMax(CRect& clientMaxRect) ////////////////////////////////////////////////////////////////////////////// long l2 = 0; -void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge) +void ConsoleView::AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dwResizeWindowEdge) { GetWindowRect(&clientRect); @@ -1053,7 +1053,7 @@ void ConsoleView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdg TRACE(L"console view: 0x%08X, adjusted: %ix%i\n", m_hWnd, dwRows, dwColumns); TRACE(L"================================================================\n"); - RecreateOffscreenBuffers(); + RecreateOffscreenBuffers(as); Repaint(true); m_consoleHandler.GetNewConsoleSize().SetReqEvent(); @@ -1104,13 +1104,16 @@ void ConsoleView::RecreateFont() } } -void ConsoleView::RecreateOffscreenBuffers() +void ConsoleView::RecreateOffscreenBuffers(ADJUSTSIZE as) { - if (!m_backgroundBrush.IsNull())m_backgroundBrush.DeleteObject(); - if (!m_bmpOffscreen.IsNull()) m_bmpOffscreen.DeleteObject(); - if (!m_bmpText.IsNull()) m_bmpText.DeleteObject(); - CreateOffscreenBuffers(); - m_bNeedFullRepaint = true; + if (!m_backgroundBrush.IsNull())m_backgroundBrush.DeleteObject(); + if( as == ADJUSTSIZE_WINDOW ) + { + if (!m_bmpOffscreen.IsNull()) m_bmpOffscreen.DeleteObject(); + if (!m_bmpText.IsNull()) m_bmpText.DeleteObject(); + } + CreateOffscreenBuffers(); + m_bNeedFullRepaint = true; } ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index b4dbb556..451cb0d9 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -100,7 +100,7 @@ class ConsoleView void GetRect(CRect& clientRect); void GetRectMax(CRect& clientMaxRect); - void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge); + void AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dwResizeWindowEdge); CPoint GetCellSize() { return CPoint(m_nCharWidth, m_nCharHeight); }; ConsoleHandler& GetConsoleHandler() { return m_consoleHandler; } @@ -112,7 +112,7 @@ class ConsoleView void SetAppActiveStatus(bool bAppActive); static void RecreateFont(); - void RecreateOffscreenBuffers(); + void RecreateOffscreenBuffers(ADJUSTSIZE as); void Repaint(bool bFullRepaint); void MainframeMoving(); diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index dc66257e..6fdbd2dd 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -278,7 +278,7 @@ LRESULT MainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, CreateAcceleratorTable(); RegisterGlobalHotkeys(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_NONE); CRect rectWindow; GetWindowRect(&rectWindow); @@ -792,7 +792,7 @@ LRESULT MainFrame::OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lPar LRESULT MainFrame::OnConsoleResized(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /* bHandled */) { - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_NONE); UpdateStatusBar(); return 0; } @@ -1093,7 +1093,7 @@ LRESULT MainFrame::OnTabMiddleClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandl LRESULT MainFrame::OnRebarHeightChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) { - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_NONE); return 0; } @@ -1477,7 +1477,7 @@ LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn } ConsoleView::RecreateFont(); - AdjustWindowSize(true); + AdjustWindowSize(ADJUSTSIZE_FONT); } RegisterGlobalHotkeys(); @@ -1659,7 +1659,7 @@ bool MainFrame::CreateNewConsole(DWORD dwTabIndex, const wstring& strStartupDir if (m_tabs.size() > 1) { CRect clientRect(0, 0, 0, 0); - tabView->AdjustRectAndResize(clientRect, WMSZ_BOTTOM); + tabView->AdjustRectAndResize(ADJUSTSIZE_WINDOW, clientRect, WMSZ_BOTTOM); UIEnable(ID_FILE_CLOSE_TAB, TRUE); } if ( g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowTabs && @@ -2022,7 +2022,7 @@ void MainFrame::ShowMenu(BOOL bShow) g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowMenu = m_bMenuVisible ? true : false; UpdateLayout(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_NONE); DockWindow(m_dockPosition); } @@ -2043,7 +2043,7 @@ void MainFrame::ShowToolbar(BOOL bShow) g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowToolbar = m_bToolbarVisible? true : false; UpdateLayout(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_NONE); DockWindow(m_dockPosition); } @@ -2062,7 +2062,7 @@ void MainFrame::ShowStatusbar(BOOL bShow) g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowStatusbar = m_bStatusBarVisible? true : false; UpdateLayout(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_NONE); DockWindow(m_dockPosition); } @@ -2094,7 +2094,7 @@ void MainFrame::ShowTabs(BOOL bShow) } UpdateLayout(); - AdjustWindowSize(false); + AdjustWindowSize(ADJUSTSIZE_NONE); DockWindow(m_dockPosition); } @@ -2121,7 +2121,7 @@ void MainFrame::ResizeWindow() if ((dwWindowWidth != m_dwWindowWidth) || (dwWindowHeight != m_dwWindowHeight)) { - AdjustWindowSize(true); + AdjustWindowSize(ADJUSTSIZE_WINDOW); } SendMessage(WM_NULL, 0, 0); @@ -2135,22 +2135,17 @@ void MainFrame::ResizeWindow() ////////////////////////////////////////////////////////////////////////////// -void MainFrame::AdjustWindowSize(bool bResizeConsole) +void MainFrame::AdjustWindowSize(ADJUSTSIZE as) { TRACE(L"AdjustWindowSize\n"); CRect clientRect(0, 0, 0, 0); - if( this->IsZoomed() ) - { - bResizeConsole = true; - } - - if (bResizeConsole) + if (as != ADJUSTSIZE_NONE) { // adjust the active view if (!m_activeTabView) return; - m_activeTabView->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge); + m_activeTabView->AdjustRectAndResize(as, clientRect, m_dwResizeWindowEdge); // for other views, first set view size and then resize their Windows consoles MutexLock viewMapLock(m_tabsMutex); @@ -2167,7 +2162,7 @@ void MainFrame::AdjustWindowSize(bool bResizeConsole) clientRect.Height(), SWP_NOMOVE|SWP_NOZORDER|SWP_NOSENDCHANGING); - it->second->AdjustRectAndResize(clientRect, m_dwResizeWindowEdge); + it->second->AdjustRectAndResize(as, clientRect, m_dwResizeWindowEdge); } } else diff --git a/Console/MainFrame.h b/Console/MainFrame.h index 30ff77f3..0e5ce70e 100644 --- a/Console/MainFrame.h +++ b/Console/MainFrame.h @@ -210,7 +210,7 @@ class MainFrame void AdjustWindowRect(CRect& rect); void SetSelectionSize(int iSelectionSize); - void AdjustWindowSize(bool bResizeConsole); + void AdjustWindowSize(ADJUSTSIZE as); void CloseTab(HWND hwndTabView); void PostMessageToConsoles(UINT Msg, WPARAM wParam, LPARAM lParam); void PasteToConsoles(); diff --git a/Console/TabView.cpp b/Console/TabView.cpp index 76e9ce81..5457b30c 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -318,12 +318,12 @@ void TabView::SetAppActiveStatus(bool bAppActive) } } -void TabView::AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge) +void TabView::AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dwResizeWindowEdge) { MutexLock viewMapLock(m_viewsMutex); for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) { - it->second->AdjustRectAndResize(clientRect, dwResizeWindowEdge); + it->second->AdjustRectAndResize(as, clientRect, dwResizeWindowEdge); } this->GetRect(clientRect); } @@ -344,7 +344,7 @@ void TabView::SplitHorizontally() CMultiSplitPane::HORIZONTAL)); CRect clientRect(0, 0, 0, 0); - AdjustRectAndResize(clientRect, WMSZ_BOTTOM); + AdjustRectAndResize(ADJUSTSIZE_WINDOW, clientRect, WMSZ_BOTTOM); } } } @@ -361,7 +361,7 @@ void TabView::SplitVertically() CMultiSplitPane::VERTICAL)); CRect clientRect(0, 0, 0, 0); - AdjustRectAndResize(clientRect, WMSZ_BOTTOM); + AdjustRectAndResize(ADJUSTSIZE_WINDOW, clientRect, WMSZ_BOTTOM); } } } @@ -393,7 +393,7 @@ bool TabView::CloseView(HWND hwnd /*= 0*/) else { CRect clientRect(0, 0, 0, 0); - AdjustRectAndResize(clientRect, WMSZ_BOTTOM); + AdjustRectAndResize(ADJUSTSIZE_WINDOW, clientRect, WMSZ_BOTTOM); } return true; @@ -446,7 +446,7 @@ void TabView::PrevView() void TabView::OnSplitBarMove(HWND /*hwndPane0*/, HWND /*hwndPane1*/, bool /*boolEnd*/) { CRect clientRect(0, 0, 0, 0); - AdjustRectAndResize(clientRect, WMSZ_BOTTOM); + AdjustRectAndResize(ADJUSTSIZE_WINDOW, clientRect, WMSZ_BOTTOM); } ///////////////////////////////////////////////////////////////////////////// diff --git a/Console/TabView.h b/Console/TabView.h index 93984375..5a0c684f 100644 --- a/Console/TabView.h +++ b/Console/TabView.h @@ -53,7 +53,7 @@ class TabView void MainframeMoving(); void Repaint(bool bFullRepaint); void InitializeScrollbars(); - void AdjustRectAndResize(CRect& clientRect, DWORD dwResizeWindowEdge); + void AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dwResizeWindowEdge); void GetRect(CRect& clientRect); void SplitHorizontally(); diff --git a/Console/stdafx.h b/Console/stdafx.h index b814ca0b..94892527 100644 --- a/Console/stdafx.h +++ b/Console/stdafx.h @@ -194,6 +194,15 @@ using namespace boost::multi_index; ////////////////////////////////////////////////////////////////////////////// + +typedef enum +{ + ADJUSTSIZE_NONE, + ADJUSTSIZE_WINDOW, + ADJUSTSIZE_FONT +} +ADJUSTSIZE; + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// From f75bbf9714aaffe714a12fdc21325bd53185ca6c Mon Sep 17 00:00:00 2001 From: cbucher Date: Mon, 29 Aug 2011 13:51:37 +0200 Subject: [PATCH 096/207] fix a crash: incoherent tree when views are removed --- Console/ConsoleView.cpp | 31 +++++++++--------- Console/TabView.cpp | 10 ++++++ wtl/wtl/include/multisplit.h | 63 ++++++++++++++++++++++++++++++------ 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 238b048a..a87ae5c7 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -977,9 +977,9 @@ void ConsoleView::GetRect(CRect& clientRect) if( width > clientRect.right ) clientRect.right = width; if( height > clientRect.bottom ) clientRect.bottom = height; - TRACE(L"========ConsoleView::GetRect=====================================\n"); - TRACE(L"wind: %ix%i - %ix%i\n", rect.left, rect.top, rect.right, rect.bottom); - TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + //TRACE(L"========ConsoleView::GetRect=====================================\n"); + //TRACE(L"wind: %ix%i - %ix%i\n", rect.left, rect.top, rect.right, rect.bottom); + //TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); } void ConsoleView::GetRectMax(CRect& clientMaxRect) @@ -997,13 +997,13 @@ void ConsoleView::GetRectMax(CRect& clientMaxRect) ////////////////////////////////////////////////////////////////////////////// -long l2 = 0; +//long l2 = 0; void ConsoleView::AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dwResizeWindowEdge) { GetWindowRect(&clientRect); - TRACE(L"========AdjustRectAndResize (%d)=================================\n", ::InterlockedIncrement(&l2)); - TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); + //TRACE(L"========AdjustRectAndResize (%d)=================================\n", ::InterlockedIncrement(&l2)); + //TRACE(L"rect: %ix%i - %ix%i\n", clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); LONG width = clientRect.right - clientRect.left; LONG height = clientRect.bottom - clientRect.top; @@ -1016,25 +1016,25 @@ void ConsoleView::AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dw width -= (m_nVInsideBorder * 2); height -= (m_nHInsideBorder * 2); - TRACE(L"exclude scrollbars and inside borders from row/col calculation\n"); - TRACE(L"width: %i height: %i\n", width, height); + //TRACE(L"exclude scrollbars and inside borders from row/col calculation\n"); + //TRACE(L"width: %i height: %i\n", width, height); DWORD dwColumns = width / m_nCharWidth; DWORD dwRows = height / m_nCharHeight; - TRACE(L"m_nCharWidth: %i m_nCharHeight: %i\n", m_nCharWidth, m_nCharHeight); + //TRACE(L"m_nCharWidth: %i m_nCharHeight: %i\n", m_nCharWidth, m_nCharHeight); DWORD dwMaxColumns = this->m_consoleHandler.GetConsoleParams()->dwMaxColumns; DWORD dwMaxRows = this->m_consoleHandler.GetConsoleParams()->dwMaxRows; - TRACE(L"dwMaxColumns: %i dwMaxRows: %i\n", dwMaxColumns, dwMaxRows); + //TRACE(L"dwMaxColumns: %i dwMaxRows: %i\n", dwMaxColumns, dwMaxRows); if( dwColumns > dwMaxColumns ) dwColumns = dwMaxColumns; if( dwRows > dwMaxRows ) dwRows = dwMaxRows; - TRACE(L"dwColumns: %i dwRows: %i\n", dwColumns, dwRows); + //TRACE(L"dwColumns: %i dwRows: %i\n", dwColumns, dwRows); clientRect.right = clientRect.left + dwColumns * m_nCharWidth + m_nVInsideBorder * 2; clientRect.bottom = clientRect.top + dwRows * m_nCharHeight + m_nHInsideBorder * 2; @@ -1050,8 +1050,8 @@ void ConsoleView::AdjustRectAndResize(ADJUSTSIZE as, CRect& clientRect, DWORD dw newConsoleSize->dwRows = dwRows; newConsoleSize->dwResizeWindowEdge = dwResizeWindowEdge; - TRACE(L"console view: 0x%08X, adjusted: %ix%i\n", m_hWnd, dwRows, dwColumns); - TRACE(L"================================================================\n"); + //TRACE(L"console view: 0x%08X, adjusted: %ix%i\n", m_hWnd, dwRows, dwColumns); + //TRACE(L"================================================================\n"); RecreateOffscreenBuffers(as); Repaint(true); @@ -1326,7 +1326,6 @@ void ConsoleView::DumpBuffer() void ConsoleView::OnConsoleChange(bool bResize) { - TRACE(L" !!!!!!!!!!!!!!! ConsoleView::OnConsoleChange(%s) !!!!!!!!!!!!!!!!", bResize?L"true":L"false"); SharedMemory& consoleParams = m_consoleHandler.GetConsoleParams(); SharedMemory& consoleInfo = m_consoleHandler.GetConsoleInfo(); SharedMemory& consoleBuffer = m_consoleHandler.GetConsoleBuffer(); @@ -1740,8 +1739,8 @@ void ConsoleView::RepaintText(CDC& dc) CRect rectWindow; GetClientRect(&rectWindow); - TRACE(L"========UpdateImageBitmap=====================================\n"); - TRACE(L"rect: %ix%i - %ix%i\n", rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom); + //TRACE(L"========UpdateImageBitmap=====================================\n"); + //TRACE(L"rect: %ix%i - %ix%i\n", rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom); g_imageHandler->UpdateImageBitmap(dc, rectWindow, m_background); diff --git a/Console/TabView.cpp b/Console/TabView.cpp index 5457b30c..6fc471f7 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -386,6 +386,16 @@ bool TabView::CloseView(HWND hwnd /*= 0*/) { iter->second->DestroyWindow(); m_views.erase(iter); + +#ifdef _DEBUG + ATLTRACE(L"%p-TabView::CloseView tree\n", + ::GetCurrentThreadId()); + multisplitClass::tree.dump(0, 0); + ATLTRACE(L"%p-TabView::CloseView defaultFocusPane\n", + ::GetCurrentThreadId()); + multisplitClass::defaultFocusPane->dump(0, multisplitClass::defaultFocusPane->parent); +#endif + multisplitClass::SetDefaultFocusPane(multisplitClass::defaultFocusPane->remove()); if( m_views.size() == 0 ) diff --git a/wtl/wtl/include/multisplit.h b/wtl/wtl/include/multisplit.h index ad6a0bf0..f9713fe5 100644 --- a/wtl/wtl/include/multisplit.h +++ b/wtl/wtl/include/multisplit.h @@ -244,19 +244,14 @@ namespace WTL this->parent->pane1: this->parent->pane0; - CMultiSplitPane* target = - this->window == this->parent->pane0->window? - this->parent->pane0: - this->parent->pane1; - ::SetWindowPos( - target->window, + this->window, 0, 0, 0, 0, 0, - SWP_HIDEWINDOW); + SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER); // parent = survivor CMultiSplitPane* result = this->parent; @@ -264,17 +259,26 @@ namespace WTL result->splitType = survivor->splitType; result->splitRatio = survivor->splitRatio; result->pane0 = survivor->pane0; + if( result->pane0 ) + result->pane0->parent = result; result->pane1 = survivor->pane1; - result->splitType = NONE; + if( result->pane1 ) + result->pane1->parent = result; // resize parent result->resize(result->width, result->height); // delete the two children of the parent - delete target; survivor->pane0 = 0; survivor->pane1 = 0; delete survivor; + delete this; + +#ifdef _DEBUG + ATLTRACE(L"%p-remove returns\n", + ::GetCurrentThreadId()); + result->dump(0, result->parent); +#endif return result; } @@ -545,7 +549,48 @@ namespace WTL dc.DrawEdge (&rect, EDGE_RAISED, this->splitType == VERTICAL? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM)); } } +#ifdef _DEBUG + void dump(int level, CMultiSplitPane* parent) + { + ATLASSERT(this->parent == parent); + + wchar_t szTab [256]; + for(int i = 0; i < level; i ++) + szTab[i] = L' '; + szTab[level] = 0; + ATLTRACE(L"%p-%swindow: %p(%p)\n", + ::GetCurrentThreadId(), + szTab, + this->window, + this); + + ATLTRACE(L"%p-%sparent: %p\n", + ::GetCurrentThreadId(), + szTab, + this->parent); + + ATLTRACE(L"%p-%s size: %dx%d\n", + ::GetCurrentThreadId(), + szTab, + this->width, + this->height); + + ATLTRACE(L"%p-%s pane0: %p\n", + ::GetCurrentThreadId(), + szTab, + this->pane0); + if( this->pane0 ) + this->pane0->dump(level + 2, this); + + ATLTRACE(L"%p-%s pane1: %p\n", + ::GetCurrentThreadId(), + szTab, + this->pane1); + if( this->pane1 ) + this->pane1->dump(level + 2, this); + } +#endif private: bool isInRect(POINT point) From 3840f3e6f0118b274f1906b1ccb9a4d8cfa5845c Mon Sep 17 00:00:00 2001 From: cbucher Date: Fri, 2 Sep 2011 11:49:17 +0200 Subject: [PATCH 097/207] fix show/hide menu,toolbars,statusbar,tabs the size of the application does not change, consoles are resized --- Console/MainFrame.cpp | 15 +++++++++------ Console/TabView.cpp | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 6fdbd2dd..eef8a591 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -1093,7 +1093,8 @@ LRESULT MainFrame::OnTabMiddleClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandl LRESULT MainFrame::OnRebarHeightChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) { - AdjustWindowSize(ADJUSTSIZE_NONE); + TRACE(L"MainFrame::OnRebarHeightChanged\n"); + AdjustWindowSize(ADJUSTSIZE_WINDOW); return 0; } @@ -1477,7 +1478,7 @@ LRESULT MainFrame::OnEditSettings(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWn } ConsoleView::RecreateFont(); - AdjustWindowSize(ADJUSTSIZE_FONT); + AdjustWindowSize(ADJUSTSIZE_WINDOW); } RegisterGlobalHotkeys(); @@ -2022,7 +2023,7 @@ void MainFrame::ShowMenu(BOOL bShow) g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowMenu = m_bMenuVisible ? true : false; UpdateLayout(); - AdjustWindowSize(ADJUSTSIZE_NONE); + AdjustWindowSize(ADJUSTSIZE_WINDOW); DockWindow(m_dockPosition); } @@ -2043,7 +2044,7 @@ void MainFrame::ShowToolbar(BOOL bShow) g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowToolbar = m_bToolbarVisible? true : false; UpdateLayout(); - AdjustWindowSize(ADJUSTSIZE_NONE); + AdjustWindowSize(ADJUSTSIZE_WINDOW); DockWindow(m_dockPosition); } @@ -2062,7 +2063,7 @@ void MainFrame::ShowStatusbar(BOOL bShow) g_settingsHandler->GetAppearanceSettings().controlsSettings.bShowStatusbar = m_bStatusBarVisible? true : false; UpdateLayout(); - AdjustWindowSize(ADJUSTSIZE_NONE); + AdjustWindowSize(ADJUSTSIZE_WINDOW); DockWindow(m_dockPosition); } @@ -2094,7 +2095,7 @@ void MainFrame::ShowTabs(BOOL bShow) } UpdateLayout(); - AdjustWindowSize(ADJUSTSIZE_NONE); + AdjustWindowSize(ADJUSTSIZE_WINDOW); DockWindow(m_dockPosition); } @@ -2172,6 +2173,8 @@ void MainFrame::AdjustWindowSize(ADJUSTSIZE as) m_activeTabView->GetRect(clientRect); } + TRACE(L"AdjustWindowSize 0: %ix%i\n", clientRect.Width(), clientRect.Height()); + AdjustWindowRect(clientRect); TRACE(L"AdjustWindowSize 1: %ix%i\n", clientRect.Width(), clientRect.Height()); diff --git a/Console/TabView.cpp b/Console/TabView.cpp index 6fc471f7..e3646f2d 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -108,6 +108,7 @@ LRESULT TabView::OnSize (UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & bHa { if (wParam != SIZE_MINIMIZED && m_mainFrame.m_bOnCreateDone) { + TRACE(L"TabView::OnSize -> multisplitClass::RectSet\n"); multisplitClass::RectSet(); // to ClientRect } From d1a1c49d56187fb9e7692af624bc556c59849e85 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 4 Sep 2011 16:28:12 +0200 Subject: [PATCH 098/207] one background for the whole tab --- Console/ConsoleView.cpp | 134 ++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 61 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index a87ae5c7..e6e1cf9d 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -1736,39 +1736,42 @@ void ConsoleView::RepaintText(CDC& dc) } else { - CRect rectWindow; - GetClientRect(&rectWindow); + CRect rectView; + GetClientRect(&rectView); + CRect rectTab; + ::GetClientRect(this->m_hwndTabView, &rectTab); + CPoint pointView(0,0); + ClientToScreen(&pointView); + CPoint pointTab(0,0); + ::ClientToScreen(this->m_hwndTabView, &pointTab); - //TRACE(L"========UpdateImageBitmap=====================================\n"); - //TRACE(L"rect: %ix%i - %ix%i\n", rectWindow.left, rectWindow.top, rectWindow.right, rectWindow.bottom); + //TRACE(L"========UpdateImageBitmap=====================================\n" + // L"rect: %ix%i - %ix%i\n", rectTab.left, rectTab.top, rectTab.right, rectTab.bottom); - g_imageHandler->UpdateImageBitmap(dc, rectWindow, m_background); + g_imageHandler->UpdateImageBitmap(dc, rectTab, m_background); if (m_tabData->imageData.bRelative) { - CPoint pointClientScreen(0, 0); - ClientToScreen(&pointClientScreen); - dc.BitBlt( - rectWindow.left, - rectWindow.top, - rectWindow.right, - rectWindow.bottom, - m_background->dcImage, - rectWindow.left + pointClientScreen.x - ::GetSystemMetrics(SM_XVIRTUALSCREEN), - rectWindow.top + pointClientScreen.y - ::GetSystemMetrics(SM_YVIRTUALSCREEN), + rectView.left, + rectView.top, + rectView.right, + rectView.bottom, + m_background->dcImage, + rectView.left + pointView.x - ::GetSystemMetrics(SM_XVIRTUALSCREEN), + rectView.top + pointView.y - ::GetSystemMetrics(SM_YVIRTUALSCREEN), SRCCOPY); } else { dc.BitBlt( - bitmapRect.left, - bitmapRect.top, - bitmapRect.right, - bitmapRect.bottom, - m_background->dcImage, - bitmapRect.left, - bitmapRect.top, + bitmapRect.left, + bitmapRect.top, + bitmapRect.right, + bitmapRect.bottom, + m_background->dcImage, + bitmapRect.left + pointView.x - pointTab.x, + bitmapRect.top + pointView.y - pointTab.y, SRCCOPY); } } @@ -1915,10 +1918,22 @@ void ConsoleView::RepaintTextChanges(CDC& dc) MutexLock bufferLock(m_consoleHandler.m_bufferMutex); - CRect rectWindow; - GetClientRect(&rectWindow); + CRect rectView; + GetClientRect(&rectView); + CRect rectTab; + ::GetClientRect(this->m_hwndTabView, &rectTab); + CPoint pointView(0,0); + ClientToScreen(&pointView); + CPoint pointTab(0,0); + ::ClientToScreen(this->m_hwndTabView, &pointTab); - if (m_tabData->backgroundImageType != bktypeNone) g_imageHandler->UpdateImageBitmap(dc, rectWindow, m_background); + if (m_tabData->backgroundImageType != bktypeNone) + { + //TRACE(L"========UpdateImageBitmap=====================================\n" + // L"rect: %ix%i - %ix%i\n", rectTab.left, rectTab.top, rectTab.right, rectTab.bottom); + + g_imageHandler->UpdateImageBitmap(dc, rectTab, m_background); + } for (DWORD i = 0; i < m_dwScreenRows; ++i, dwY += m_nCharHeight) { @@ -1938,7 +1953,7 @@ void ConsoleView::RepaintTextChanges(CDC& dc) rect.bottom = dwY + m_nCharHeight; // we have to erase two spaces for double-width characters rect.right = (m_screenBuffer[dwOffset].charInfo.Attributes & COMMON_LVB_LEADING_BYTE) ? dwX + 2*m_nCharWidth : dwX + m_nCharWidth; - + if (m_tabData->backgroundImageType == bktypeNone) { dc.FillRect(&rect, m_backgroundBrush); @@ -1947,29 +1962,26 @@ void ConsoleView::RepaintTextChanges(CDC& dc) { if (m_tabData->imageData.bRelative) { - CPoint pointClientScreen(0, 0); - ClientToScreen(&pointClientScreen); - dc.BitBlt( - rect.left, - rect.top, - rect.Width(), - rect.Height(), - m_background->dcImage, - rect.left + pointClientScreen.x - ::GetSystemMetrics(SM_XVIRTUALSCREEN), - rect.top + pointClientScreen.y - ::GetSystemMetrics(SM_YVIRTUALSCREEN), + rect.left, + rect.top, + rect.Width(), + rect.Height(), + m_background->dcImage, + rect.left + pointView.x - ::GetSystemMetrics(SM_XVIRTUALSCREEN), + rect.top + pointView.y - ::GetSystemMetrics(SM_YVIRTUALSCREEN), SRCCOPY); } else { dc.BitBlt( - rect.left, - rect.top, + rect.left, + rect.top, rect.Width(), rect.Height(), - m_background->dcImage, - rect.left, - rect.top, + m_background->dcImage, + rect.left + pointView.x - pointTab.x, + rect.top + pointView.y - pointTab.y, SRCCOPY); } } @@ -2071,8 +2083,8 @@ void ConsoleView::UpdateOffscreen(const CRect& rectBlit) rectCursor.bottom += (consoleInfo->csbi.dwCursorPosition.Y - consoleInfo->csbi.srWindow.Top) * m_nCharHeight + m_nHInsideBorder; m_cursor->BitBlt( - m_dcOffscreen, - rectCursor.left, + m_dcOffscreen, + rectCursor.left, rectCursor.top); } } @@ -2101,18 +2113,18 @@ void ConsoleView::SendTextToConsole(const wchar_t* pszText) void* pRemoteMemory = ::VirtualAllocEx( m_consoleHandler.GetConsoleHandle().get(), - NULL, - (textLen+1)*sizeof(wchar_t), - MEM_COMMIT, + NULL, + (textLen+1)*sizeof(wchar_t), + MEM_COMMIT, PAGE_READWRITE); if (pRemoteMemory == NULL) return; if (!::WriteProcessMemory( m_consoleHandler.GetConsoleHandle().get(), - pRemoteMemory, - (PVOID)pszText, - (textLen+1)*sizeof(wchar_t), + pRemoteMemory, + (PVOID)pszText, + (textLen+1)*sizeof(wchar_t), NULL)) { ::VirtualFreeEx(m_consoleHandler.GetConsoleHandle().get(), pRemoteMemory, NULL, MEM_RELEASE); @@ -2139,28 +2151,28 @@ bool ConsoleView::TranslateKeyDown(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/) { switch(wParam) { - case VK_UP: - DoScroll(SB_VERT, SB_LINEUP, 0); + case VK_UP: + DoScroll(SB_VERT, SB_LINEUP, 0); return true; - case VK_PRIOR: - DoScroll(SB_VERT, SB_PAGEUP, 0); + case VK_PRIOR: + DoScroll(SB_VERT, SB_PAGEUP, 0); return true; - case VK_DOWN: - DoScroll(SB_VERT, SB_LINEDOWN, 0); + case VK_DOWN: + DoScroll(SB_VERT, SB_LINEDOWN, 0); return true; - case VK_NEXT: - DoScroll(SB_VERT, SB_PAGEDOWN, 0); + case VK_NEXT: + DoScroll(SB_VERT, SB_PAGEDOWN, 0); return true; - case VK_LEFT: - DoScroll(SB_HORZ, SB_LINELEFT, 0); + case VK_LEFT: + DoScroll(SB_HORZ, SB_LINELEFT, 0); return true; - case VK_RIGHT: - DoScroll(SB_HORZ, SB_LINERIGHT, 0); + case VK_RIGHT: + DoScroll(SB_HORZ, SB_LINERIGHT, 0); return true; } } From 4e51e3dec7b9f250a0dbc8b2a6ca25c254f8366c Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 4 Sep 2011 16:48:50 +0200 Subject: [PATCH 099/207] undo last commit --- Console/ConsoleView.cpp | 12 ++++++++++-- Console/ConsoleView.h | 1 + Console/MainFrame.cpp | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 118c6c46..fe4ab760 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -234,7 +234,6 @@ LRESULT ConsoleView::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ LRESULT ConsoleView::OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { - m_bResizing = true; return 1; } @@ -263,7 +262,6 @@ LRESULT ConsoleView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ if (m_bResizing) { dc.FillRect(&dc.m_ps.rcPaint, m_backgroundBrush); - m_bResizing = false; } dc.BitBlt( @@ -1142,6 +1140,16 @@ void ConsoleView::MainframeMoving() ////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +void ConsoleView::SetResizing(bool bResizing) +{ + m_bResizing = bResizing; +} + +////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////// void ConsoleView::SetActive(bool bActive) diff --git a/Console/ConsoleView.h b/Console/ConsoleView.h index 566a1a68..ddad483b 100644 --- a/Console/ConsoleView.h +++ b/Console/ConsoleView.h @@ -116,6 +116,7 @@ class ConsoleView void Repaint(bool bFullRepaint); void MainframeMoving(); + void SetResizing(bool bResizing); void SetActive(bool bActive); void SetTitle(const CString& strTitle); const CString& GetTitle() const { return m_strTitle; } diff --git a/Console/MainFrame.cpp b/Console/MainFrame.cpp index 2669283f..b83dc5ef 100644 --- a/Console/MainFrame.cpp +++ b/Console/MainFrame.cpp @@ -549,6 +549,8 @@ LRESULT MainFrame::OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& / if (!m_activeView) return 0; + m_activeView->SetResizing(true); + CPoint pointSize = m_activeView->GetCellSize(); RECT *rectNew = (RECT *)lParam; @@ -2068,6 +2070,8 @@ void MainFrame::ResizeWindow() SendMessage(WM_NULL, 0, 0); m_dwResizeWindowEdge = WMSZ_BOTTOM; + + if (m_activeView) m_activeView->SetResizing(false); } ////////////////////////////////////////////////////////////////////////////// From b80cb44a2fd6368d31f81c7c7d8fbb2033cd56e6 Mon Sep 17 00:00:00 2001 From: cbucher Date: Mon, 5 Sep 2011 11:49:20 +0200 Subject: [PATCH 100/207] new visualize the selected cursor in settings dialog --- Console/Console.rc | 1 + Console/ConsoleView.cpp | 2 +- Console/PageSettingsTabs1.cpp | 65 +++++++++++++++++++++++++++++++++++ Console/PageSettingsTabs1.h | 17 +++++++-- Console/resource.h | 1 + 5 files changed, 82 insertions(+), 4 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index 555c5b28..a43cf36a 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -430,6 +430,7 @@ BEGIN CONTROL "",IDC_CURSOR_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,140,133,16,14,WS_EX_DLGMODALFRAME GROUPBOX "Cursor",IDC_STATIC,0,120,194,37,0,WS_EX_TRANSPARENT GROUPBOX "Title && icon",IDC_STATIC,0,3,217,50,0,WS_EX_TRANSPARENT + CONTROL "",IDC_CURSOR_ANIM,"Static",SS_BLACKRECT | SS_REALSIZEIMAGE | SS_SUNKEN,176,131,14,18 END IDD_SETTINGS_TABS_2 DIALOGEX 0, 0, 223, 172 diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index e6e1cf9d..efb862b2 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -1452,7 +1452,7 @@ void ConsoleView::CreateOffscreenBuffers() m_tabData.get() ? static_cast(m_tabData->dwCursorStyle) : cstyleXTerm, dcWindow, rectCursor, - m_tabData.get() ? static_cast(m_tabData->crCursorColor) : RGB(255, 255, 255)); + m_tabData.get() ? m_tabData->crCursorColor : RGB(255, 255, 255)); } ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/PageSettingsTabs1.cpp b/Console/PageSettingsTabs1.cpp index 80592931..c51d989f 100644 --- a/Console/PageSettingsTabs1.cpp +++ b/Console/PageSettingsTabs1.cpp @@ -42,6 +42,7 @@ LRESULT PageSettingsTabs1::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM if (CTheme().IsThemingSupported()) ::EnableThemeDialogTexture(m_hWnd, ETDT_USETABTEXTURE); + m_staticCursorAnim.Attach(GetDlgItem(IDC_CURSOR_ANIM)); m_comboCursor.Attach(GetDlgItem(IDC_COMBO_CURSOR)); m_staticCursorColor.Attach(GetDlgItem(IDC_CURSOR_COLOR)); @@ -76,6 +77,8 @@ LRESULT PageSettingsTabs1::OnCtlColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM m_staticCursorColor.GetClientRect(&rect); dc.FillRect(&rect, brush); + + SetCursor(); return 0; } @@ -275,3 +278,65 @@ void PageSettingsTabs1::Save() } ////////////////////////////////////////////////////////////////////////////// + +LRESULT PageSettingsTabs1::OnCbnSelchangeComboCursor(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + SetCursor(); + + return 0; +} + +LRESULT PageSettingsTabs1::OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + if ((wParam == CURSOR_TIMER) && (m_cursor.get() != NULL)) + { + DrawCursor(); + } + + return 0; +} + +void PageSettingsTabs1::SetCursor(void) +{ + CRect rectCursorAnim; + m_staticCursorAnim.GetClientRect(&rectCursorAnim); + CClientDC dc(m_staticCursorAnim.m_hWnd); + CBrush brush(::CreateSolidBrush(RGB(0,0,0))); + dc.FillRect(rectCursorAnim, brush); + + rectCursorAnim.right -= 8; + rectCursorAnim.bottom -= 8; + + m_cursor.reset(); + m_cursor = CursorFactory::CreateCursor( + m_hWnd, + true, + static_cast(m_comboCursor.GetCurSel()), + dc, + rectCursorAnim, + m_tabData->crCursorColor); + + DrawCursor(); +} + +void PageSettingsTabs1::DrawCursor(void) +{ + m_staticCursorAnim.RedrawWindow(); + + CClientDC dc(m_staticCursorAnim.m_hWnd); + CBrush brush(::CreateSolidBrush(RGB(0,0,0))); + CPen pen(::CreatePen(PS_SOLID, 2, RGB(255,255,255))); + CRect rectCursorAnim; + m_staticCursorAnim.GetClientRect(&rectCursorAnim); + + dc.FillRect(rectCursorAnim, brush); + dc.SelectPen(pen); + dc.MoveTo(rectCursorAnim.left + 7, rectCursorAnim.top + 7); + dc.LineTo(rectCursorAnim.right - 7, rectCursorAnim.bottom - 7); + dc.MoveTo(rectCursorAnim.right - 7, rectCursorAnim.top + 7); + dc.LineTo(rectCursorAnim.left + 7, rectCursorAnim.bottom - 7); + + m_cursor->PrepareNext(); + m_cursor->Draw(true); + m_cursor->BitBlt(dc, 4, 4); +} \ No newline at end of file diff --git a/Console/PageSettingsTabs1.h b/Console/PageSettingsTabs1.h index 849df0c0..b4ad6cd8 100644 --- a/Console/PageSettingsTabs1.h +++ b/Console/PageSettingsTabs1.h @@ -1,6 +1,7 @@ - #pragma once +#include "Cursors.h" + ////////////////////////////////////////////////////////////////////////////// @@ -36,6 +37,7 @@ class PageSettingsTabs1 BEGIN_MSG_MAP(PageSettingsTabs1) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnCtlColorStatic) + MESSAGE_HANDLER(WM_TIMER, OnTimer) COMMAND_HANDLER(IDC_TAB_TITLE, EN_CHANGE, OnTabTitleChange) COMMAND_HANDLER(IDC_TAB_ICON, EN_CHANGE, OnTabIconChange) @@ -45,7 +47,8 @@ class PageSettingsTabs1 COMMAND_ID_HANDLER(IDC_BTN_BROWSE_DIR, OnClickedBtnBrowseDir) COMMAND_ID_HANDLER(IDC_CHECK_DEFAULT_ICON, OnCheckboxClicked) COMMAND_ID_HANDLER(IDC_CHECK_RUN_AS_USER, OnCheckboxClicked) - END_MSG_MAP() + COMMAND_HANDLER(IDC_COMBO_CURSOR, CBN_SELCHANGE, OnCbnSelchangeComboCursor) + END_MSG_MAP() // Handler prototypes (uncomment arguments if needed): // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) @@ -55,6 +58,7 @@ class PageSettingsTabs1 LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnCtlColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnTabTitleChange(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnTabIconChange(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); @@ -74,10 +78,15 @@ class PageSettingsTabs1 const CString& GetTabShell() const { return m_strShell; } const int UseDefaultIcon() const { return m_nUseDefaultIcon; } - private: +private: + void SetCursor(void); + void DrawCursor(void); + private: + shared_ptr m_cursor; shared_ptr m_tabData; + CStatic m_staticCursorAnim; CComboBox m_comboCursor; CStatic m_staticCursorColor; @@ -89,6 +98,8 @@ class PageSettingsTabs1 CString m_strInitialDir; bool m_bRunAsUser; CString m_strUser; +public: + LRESULT OnCbnSelchangeComboCursor(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/resource.h b/Console/resource.h index 39b0146e..1651b917 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -159,6 +159,7 @@ #define IDC_COMBO_CURSOR 1121 #define IDC_CURSOR_COLOR 1122 #define IDC_RADIO_BK_TYPE 1123 +#define IDC_CURSOR_ANIM 1123 #define IDC_RADIO_BK_TYPE2 1124 #define IDC_RADIO_BK_TYPE3 1125 #define IDC_BK_COLOR 1126 From aca892397094a2ca86d66c4a95f02dd08b01c98b Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 10 Sep 2011 15:37:25 +0200 Subject: [PATCH 101/207] new support strech with preserve aspect ratio --- Console/Console.rc | 4 +- Console/ImageHandler.cpp | 138 +++++++++++++++++++++------------- Console/ImageHandler.h | 7 +- Console/PageSettingsTabs2.cpp | 1 + 4 files changed, 93 insertions(+), 57 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index a43cf36a..fb806490 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -448,8 +448,8 @@ BEGIN PUSHBUTTON "...",IDC_BTN_BROWSE_BK,196,46,15,14 CONTROL "Relative",IDC_CHECK_BK_RELATIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,65,42,10 CONTROL "Extend across monitors",IDC_CHECK_BK_EXTEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,80,91,10 - LTEXT "Position:",IDC_STATIC_BK_POS,116,66,28,8,NOT WS_GROUP - COMBOBOX IDC_COMBO_BK_POS,145,64,48,53,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Position:",IDC_STATIC_BK_POS,100,66,28,8,NOT WS_GROUP + COMBOBOX IDC_COMBO_BK_POS,130,64,63,53,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Tint col&or:",IDC_STATIC_TINT_COLOR,12,116,33,8,NOT WS_GROUP CONTROL "",IDC_TINT_COLOR,"Static",SS_BLACKFRAME | SS_NOTIFY,47,113,16,14,WS_EX_DLGMODALFRAME LTEXT "Tint opacity",IDC_STATIC_TINT_OPACITY,13,132,38,8,NOT WS_GROUP diff --git a/Console/ImageHandler.cpp b/Console/ImageHandler.cpp index b1b9c652..376e5a67 100644 --- a/Console/ImageHandler.cpp +++ b/Console/ImageHandler.cpp @@ -273,46 +273,63 @@ void ImageHandler::CreateRelativeImage(const CDC& dc, shared_ptroriginalImage->getWidth(); - DWORD dwTemplateHeight = bkImage->originalImage->getHeight(); + DWORD dwTemplateWidth = bkImage->originalImage->getWidth(); + DWORD dwTemplateHeight = bkImage->originalImage->getHeight(); - if (bkImage->imageData.imagePosition == imgPosFit) + if (bkImage->imageData.imagePosition == imgPosFit || bkImage->imageData.imagePosition == imgPosFitWithAspectRatio) { if (bkImage->imageData.bExtend) { - dwTemplateWidth = bkImage->dwImageWidth; - dwTemplateHeight= bkImage->dwImageHeight; + dwTemplateWidth = bkImage->dwImageWidth; + dwTemplateHeight = bkImage->dwImageHeight; } else { - dwTemplateWidth = dwPrimaryDisplayWidth; - dwTemplateHeight= dwPrimaryDisplayHeight; + dwTemplateWidth = dwPrimaryDisplayWidth; + dwTemplateHeight = dwPrimaryDisplayHeight; } } - if ((bkImage->originalImage->getWidth() != dwTemplateWidth) || - (bkImage->originalImage->getHeight() != dwTemplateHeight)) + WORD wNewWidth = static_cast(dwTemplateWidth); + WORD wNewHeight = static_cast(dwTemplateHeight); + + if ((bkImage->originalImage->getWidth() != wNewWidth) || + (bkImage->originalImage->getHeight() != wNewHeight)) { // resize background image fipImage tempImage(*(bkImage->originalImage)); - tempImage.rescale(static_cast(dwTemplateWidth), static_cast(dwTemplateHeight), FILTER_BILINEAR); + if( bkImage->imageData.imagePosition == imgPosFitWithAspectRatio ) + { + double dXRatio = (double)wNewWidth / (double)bkImage->originalImage->getWidth (); + double dYRatio = (double)wNewHeight / (double)bkImage->originalImage->getHeight(); + + if( dXRatio < dYRatio ) + { + wNewHeight = (WORD)::MulDiv(bkImage->originalImage->getHeight(), wNewWidth, bkImage->originalImage->getWidth()); + } + else + { + wNewWidth = (WORD)::MulDiv(bkImage->originalImage->getWidth(), wNewHeight, bkImage->originalImage->getHeight()); + } + } + tempImage.rescale(wNewWidth, wNewHeight, FILTER_BILINEAR); bmpTemplate.CreateDIBitmap( - dc, - tempImage.getInfoHeader(), - CBM_INIT, - tempImage.accessPixels(), - tempImage.getInfo(), + dc, + tempImage.getInfoHeader(), + CBM_INIT, + tempImage.accessPixels(), + tempImage.getInfo(), DIB_RGB_COLORS); } else { bmpTemplate.CreateDIBitmap( - dc, - bkImage->originalImage->getInfoHeader(), - CBM_INIT, - bkImage->originalImage->accessPixels(), - bkImage->originalImage->getInfo(), + dc, + bkImage->originalImage->getInfoHeader(), + CBM_INIT, + bkImage->originalImage->accessPixels(), + bkImage->originalImage->getInfo(), DIB_RGB_COLORS); } @@ -321,9 +338,9 @@ void ImageHandler::CreateRelativeImage(const CDC& dc, shared_ptrimageData.imagePosition == imgPosTile) { TileTemplateImage( - dcTemplate, - ::GetSystemMetrics(SM_XVIRTUALSCREEN), - ::GetSystemMetrics(SM_YVIRTUALSCREEN), + dcTemplate, + ::GetSystemMetrics(SM_XVIRTUALSCREEN), + ::GetSystemMetrics(SM_YVIRTUALSCREEN), bkImage); } @@ -332,13 +349,13 @@ void ImageHandler::CreateRelativeImage(const CDC& dc, shared_ptrimageData.bExtend) { PaintTemplateImage( - dcTemplate, - 0, + dcTemplate, 0, - bkImage->dwImageWidth, - bkImage->dwImageHeight, - bkImage->dwImageWidth, - bkImage->dwImageHeight, + 0, + wNewWidth, + wNewHeight, + bkImage->dwImageWidth, + bkImage->dwImageHeight, bkImage); } else @@ -385,29 +402,46 @@ void ImageHandler::CreateImage(const CDC& dc, const CRect& clientRect, shared_pt dcTemplate.CreateCompatibleDC(NULL); - if ((bkImage->imageData.imagePosition == imgPosFit) && - ((bkImage->originalImage->getWidth() != bkImage->dwImageWidth) || (bkImage->originalImage->getHeight() != bkImage->dwImageHeight))) + WORD wNewWidth = static_cast(bkImage->dwImageWidth); + WORD wNewHeight = static_cast(bkImage->dwImageHeight); + + if ((bkImage->imageData.imagePosition == imgPosFit || bkImage->imageData.imagePosition == imgPosFitWithAspectRatio) && + ((bkImage->originalImage->getWidth() != wNewWidth) || (bkImage->originalImage->getHeight() != wNewHeight))) { // resize background image fipImage tempImage(*(bkImage->originalImage)); - tempImage.rescale(static_cast(bkImage->dwImageWidth), static_cast(bkImage->dwImageHeight), FILTER_BILINEAR); + if( bkImage->imageData.imagePosition == imgPosFitWithAspectRatio ) + { + double dXRatio = (double)wNewWidth / (double)bkImage->originalImage->getWidth (); + double dYRatio = (double)wNewHeight / (double)bkImage->originalImage->getHeight(); + + if( dXRatio < dYRatio ) + { + wNewHeight = (WORD)::MulDiv(bkImage->originalImage->getHeight(), wNewWidth, bkImage->originalImage->getWidth()); + } + else + { + wNewWidth = (WORD)::MulDiv(bkImage->originalImage->getWidth(), wNewHeight, bkImage->originalImage->getHeight()); + } + } + tempImage.rescale(wNewWidth, wNewHeight, FILTER_BILINEAR); bmpTemplate.CreateDIBitmap( - dc, - tempImage.getInfoHeader(), - CBM_INIT, - tempImage.accessPixels(), - tempImage.getInfo(), + dc, + tempImage.getInfoHeader(), + CBM_INIT, + tempImage.accessPixels(), + tempImage.getInfo(), DIB_RGB_COLORS); } else { bmpTemplate.CreateDIBitmap( - dc, - bkImage->originalImage->getInfoHeader(), - CBM_INIT, - bkImage->originalImage->accessPixels(), - bkImage->originalImage->getInfo(), + dc, + bkImage->originalImage->getInfoHeader(), + CBM_INIT, + bkImage->originalImage->accessPixels(), + bkImage->originalImage->getInfo(), DIB_RGB_COLORS); } @@ -416,22 +450,22 @@ void ImageHandler::CreateImage(const CDC& dc, const CRect& clientRect, shared_pt if (bkImage->imageData.imagePosition == imgPosTile) { TileTemplateImage( - dcTemplate, - 0, - 0, + dcTemplate, + 0, + 0, bkImage); } else { PaintTemplateImage( - dcTemplate, - 0, + dcTemplate, + 0, 0, - bkImage->dwImageWidth, - bkImage->dwImageHeight, - bkImage->dwImageWidth, - bkImage->dwImageHeight, + wNewWidth, + wNewHeight, + bkImage->dwImageWidth, + bkImage->dwImageHeight, bkImage); } } @@ -446,7 +480,7 @@ void ImageHandler::CreateImage(const CDC& dc, const CRect& clientRect, shared_pt void ImageHandler::PaintTemplateImage(const CDC& dcTemplate, int nOffsetX, int nOffsetY, DWORD dwSrcWidth, DWORD dwSrcHeight, DWORD dwDstWidth, DWORD dwDstHeight, shared_ptr& bkImage) { - if (bkImage->imageData.imagePosition == imgPosCenter) + if (bkImage->imageData.imagePosition == imgPosCenter) { bkImage->dcImage.BitBlt( (dwDstWidth <= bkImage->dwOriginalImageWidth) ? nOffsetX : nOffsetX + (dwDstWidth - bkImage->dwOriginalImageWidth)/2, diff --git a/Console/ImageHandler.h b/Console/ImageHandler.h index 42e0d9dd..117bd4ba 100644 --- a/Console/ImageHandler.h +++ b/Console/ImageHandler.h @@ -6,9 +6,10 @@ enum ImagePosition { - imgPosCenter = 0, - imgPosFit = 1, - imgPosTile = 2 + imgPosCenter = 0, + imgPosFit = 1, + imgPosTile = 2, + imgPosFitWithAspectRatio = 3 }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/PageSettingsTabs2.cpp b/Console/PageSettingsTabs2.cpp index e30c494f..5c366cd8 100644 --- a/Console/PageSettingsTabs2.cpp +++ b/Console/PageSettingsTabs2.cpp @@ -40,6 +40,7 @@ LRESULT PageSettingsTabs2::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM m_comboBkPosition.AddString(L"Center"); m_comboBkPosition.AddString(L"Stretch"); m_comboBkPosition.AddString(L"Tile"); + m_comboBkPosition.AddString(L"Stretch/AR"); m_staticTintOpacity.Attach(GetDlgItem(IDC_TINT_OPACITY_VAL)); m_sliderTintOpacity.Attach(GetDlgItem(IDC_TINT_OPACITY)); From af4e20db6470f410c31fd6e05bf4b2831850ba55 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sat, 24 Sep 2011 10:22:20 +0200 Subject: [PATCH 102/207] about : ConsoleZ 1.00.0 --- Console/AboutDlg.cpp | 18 ++++++------- Console/AboutDlg.h | 55 ++++++++++++++++++++++++++++++++++++++++ Console/Console.rc | 12 +++++---- Console/res/Console.ico | Bin 18902 -> 85369 bytes Console/stdafx.h | 4 +-- 5 files changed, 72 insertions(+), 17 deletions(-) diff --git a/Console/AboutDlg.cpp b/Console/AboutDlg.cpp index 2ce84d52..e6407c9f 100644 --- a/Console/AboutDlg.cpp +++ b/Console/AboutDlg.cpp @@ -9,19 +9,17 @@ LRESULT CAboutDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { - CWindow staticMessage(GetDlgItem(IDC_STATIC_VERSION)); - CString strMsg; - - strMsg.Format(L"\nConsole %i.%02i.%i\n", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); - staticMessage.SetWindowText(strMsg); - - CenterWindow(GetParent()); - #ifdef _USE_AERO AERO_CONTROL(CButton, m_Ok, IDOK) - AERO_CONTROL(CStatic, m_Version, IDC_STATIC_VERSION) - AERO_CONTROL(CStatic, m_Text, IDC_APPTEXT) + this->OpenThemeData(VSCLASS_WINDOW); +#else + CString strMsg; + strMsg.Format(L"\nConsoleZ %i.%02i.%i\n", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); + + CWindow staticMessage(GetDlgItem(IDC_STATIC_VERSION)); + staticMessage.SetWindowText(strMsg); #endif + CenterWindow(GetParent()); return TRUE; } diff --git a/Console/AboutDlg.h b/Console/AboutDlg.h index 0f6eaea3..141042bb 100644 --- a/Console/AboutDlg.h +++ b/Console/AboutDlg.h @@ -30,4 +30,59 @@ class CAboutDlg : LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); +#ifdef _USE_AERO + void Paint(CDCHandle dc, RECT& rClient, RECT& rView, RECT& rDest) + { + aero::CDialogImpl::Paint(dc, rClient, rView, rDest); + + CPaintDC(*this); + Gdiplus::Graphics gr(dc); + + CIcon icon (static_cast( + ::LoadImage( + ::GetModuleHandle(NULL), + MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, + 256, + 256, + LR_DEFAULTCOLOR))); + + //get the icon info + ICONINFO ii; + GetIconInfo(icon, &ii); + + //create a bitmap from the ICONINFO so we can access the bitmapData + Gdiplus::Bitmap bmpIcon(ii.hbmColor, NULL); + Gdiplus::Rect rectBounds(0, 0, bmpIcon.GetWidth(), bmpIcon.GetHeight() ); + + //get the BitmapData + Gdiplus::BitmapData bmData; + bmpIcon.LockBits(&rectBounds, Gdiplus::ImageLockModeRead, + bmpIcon.GetPixelFormat(), &bmData); + + // create a new 32 bit bitmap using the bitmapData + Gdiplus::Bitmap bmpAlpha(bmData.Width, bmData.Height, bmData.Stride, + PixelFormat32bppARGB, (BYTE*)bmData.Scan0); + bmpIcon.UnlockBits(&bmData); + + gr.DrawImage(&bmpAlpha, 0, 0); + + DTTOPTS dtto = { 0 }; + dtto.dwSize = sizeof(DTTOPTS); + dtto.iGlowSize = 8; + dtto.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE; + + CRect rectVersion(0x25,0x41,0x25+0x78,0x41+0x25); + CString strMsgVersion; + strMsgVersion.Format(L"\nConsoleZ %i.%02i.%i\n", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); + this->DrawTextW(dc, strMsgVersion, rectVersion, DT_CENTER | DT_VCENTER, dtto); + + CRect rectAppText(0x14,0x64,0x14+0x9A,0x64+0x80); + this->DrawTextW( + dc, + L"\nCopyright (C) 2011\nChristophe Bucher\n\na modified version of\nConsole 2\nfrom\nMarko Bozikovic", + rectAppText, + DT_CENTER | DT_VCENTER, dtto); + } +#endif }; diff --git a/Console/Console.rc b/Console/Console.rc index fb806490..f5705190 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -113,16 +113,18 @@ END // Dialog // -IDD_ABOUTBOX DIALOGEX 0, 0, 187, 131 +IDD_ABOUTBOX DIALOGEX 0, 0, 187, 151 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - DEFPUSHBUTTON "OK",IDOK,130,110,50,14 - CTEXT "\nConsole 2.0",IDC_STATIC_VERSION,25,41,78,25,0,WS_EX_ACCEPTFILES + DEFPUSHBUTTON "OK",IDOK,130,130,50,14 +#ifndef _USE_AERO + CTEXT "\nConsole 2.0",IDC_STATIC_VERSION,25,41,78,25 ICON IDR_MAINFRAME,IDC_APPICON,55,26,20,20 - GROUPBOX "",IDC_STATIC,7,7,115,117 - CTEXT "\nCopyright (C) 2001-2010\nMarko Bozikovic\n\nModified by\nChristophe Bucher",IDC_APPTEXT,14,64,103,53 + CTEXT "\nCopyright (C) 2011\nChristophe Bucher\n\na modified version of\nConsole 2\nfrom\nMarko Bozikovic",IDC_APPTEXT,14,64,103,80 +#endif + GROUPBOX "",IDC_STATIC,7,7,115,137 END IDD_RENAME_TAB DIALOGEX 0, 0, 202, 55 diff --git a/Console/res/Console.ico b/Console/res/Console.ico index 0b6dc468da865d237ffc1ad09634cda301781d83..5dfa288174d165b495a23741c81f7262cd57790c 100644 GIT binary patch literal 85369 zcmcF}^;=cX7w$emcN`Ag(j5ZQAR*l)Ez(F!!=a@`kP<2BP66pgkd&52y8F=A&;8zi z;qK>|XU)53*532Oo;~kc>jeN1fCBt?fdE=Sb{qio{`K+k|A%d%0FeIgo|M%8FpJDT zI}HFlJpaSR&j5fG{?C*4|KWdr6Jj7BN<&Qn2a_E0-=lC|DZbSDZ}h*0j{46SyA@jl zz&Pfsm(n`k3kLycom9G?pVECc%Wkw3pW!RXAf#x+xKyR`L(%i{LM%-l*hv<3ljro7 zU|5yKbJZLlSg`07@xrpk!-&Bc&p=v=W3#4T)1Sn*7yY(JTm7~Jf;*M2aQeA#mRn1% z@712D@QhwNI5<7o2vuF8|JMac{eu-1C_qI;L&J9xp#J;J%z_axzVQEhu+o$C?fvN0 z*W#bYMz65|qd$_tQh2&j;y2CB&bQuKn@tn=Rk;lfKu&`biUoD)m6~%R3cA>^#MajE zO388IH6DLF84iKfqk4$^KW_?bX>Vijo=BKzMOzP@t=D;r#oj_I9T?F}Bg_$baaok` zwIS%=ynk=vC~Rs(0mgsvRb$+hMSx{FnIh1b-j=iC=bAwr?kt z&&qNW-o0#x`*>W_(FkBOhg%59KT^4Hi$M;l)>hi0))5=KAv;YMx~`e{ZdrI=zxG9G zGaWV^4Ac0nj z+p8OqZkqQpgLoTCF9``h;>&CDsD98zi*g#2frqu?9Ul8>_er@3$4AEqzp( z3mBG*71&ids*L*1z2`S&#=fj=e7dF&+%6C7y~XLxz;?IH4tRCYOHGYPW-!gEFW#Sc zY%&)wX>TE0Zj8YWYWWX6I%mMW z8EDwcJgZN9fokgU^@vZ(B542%Jh|DLte@-q#7W{Ijm>tFs39cHZNTE1igcC+!XF z3G0_U_z-H5ZTCAzud1_O(7}A72d_Khb6JY``Rdn}`)mjzRN}TG%JOr<*p2@y>I!q> zO3GWK^&+8(g!@w|a2R-J0wNcDZh$|4mFj32mhHolLrwK7NoY5Yz)ch*oIrAb`vxh4 ztnxNEZ5E1ZkJ`RGDcC}c^~xN}i3FZfV_K<2Bp{76t9Ot6xo#yCslfU$LvzL# zEI7rFN7IHM6bEJA5)MlS6I#!VDV#rP7&$;%(EVF1%I81JLGQ)QGHw$C zQ)r*4c*hlLY^J7{IH6A(X(H~ZVS!Xi6wkXD+>a1_>Jrk|B9>FOAfT>M6`0#^jgjQg z+pO|YJLsK#NHnyEv@EKOZeU=y+#*Y^f#7ubMh8X4B ztN^Wf&Po~ogpa?uaH1lpUm^>niZ?X}PoI1^pGHGi9-MZ$R!<=} z{K*-DlNkohSZ8wT&u9Bq#NX;FmeD24;AkbWt$vs~O)enpyUwkeZOUd* zS!RD(bHd&kn~d@{keN>khRv>WbBBtaHlwfa#Z2itC(Uz?c%a>e<%rE;B`kZvIeafP zEi7~d5RO8=i+O$5OW&`bV*tNLTf9>Y23HipfP=yc{`)b53#AWsPlKr;y;5s-YY8AJ zNaW0DJBX=&yM2uLIv)kV)R=OezIIz>1vI+Hm?G)s7BD9|d*)Uh+|7>5f`R%HZm&3y z6dB$mxmIUEy&@yr#0uJ0;5Y!}ltVX;ftvT=wkBzAiFoTsa-L7%ss0!s|Pg5xhY~OXLqZ>njB)FK~d< z-wD|k*yx!4KG`Nk2bjlV=N>FuqB&ZJ;RDC8kf(%!9Mdx1@d@?!RPs*4K=rIoT_ES^ zmBqMG2LbSj*8E;=9xy^q2GP#k2i_VK(hjYBgXI97P*jxXjIC$tV8A~hAg2QRy+Xa9 zc}VJa=1!#7eGoOvYG)JZjWRJq1S;&&s}%|6c`O0ZDgjc&=`&LKn)G~&;I_`Lac?_z z+E`BD!Asx9@_QhH-sl}n{R9r%?YtU4!r zAppx`#WA|x7Vtq4gkKf6E&1k640Yqzu0ri{G(dw> zmgR@~_?YSt)?amgqchH1yywO1dw`6DFS+k`{b2(Z8AspO63!VQr7;^%2Z$|MksOMF zU`BrkAY}w?CsZVY(%NMudFFsQ*dy5ayDTaw7rn$O;4UqFgYG#+^7A&6W3{3?vr zxnmp0nEF)(jE^7R$#fq;&#pgfO}==A<yE2p4z;|LdM)XBYS?D<#^N%6nDz~W=fz0hacM*8uZkoa zHJ>x70S+V{SgJV0A@M%S6|?^6FGPlOIQzy!!oMn)*c%1NebKSqH`ArJK!3`y>^p}o zyz>zf-Yki?wd|W@A?or~+T>t^6>h#5)~r6#{Ps^dWbUrj@Vrku3peZR#;|HjrDFF_ zgQUZzf$TX}5_pe-3+U~{CmVp242a~wzZ~9*wp)M(&yl9(r=L$`hmA?(Drz8i4UPBtM2wV3`d~_gj1}F%yrc5MGQ|( zx@>e)x@z>%Z(w_m-;Aj2y{lt6ZO?ALSj5=B6+Uf}wOAp$>;C4o3{DtpOAY;bvE0kA zAO$<_O9I5K?|Vhz%MaHZlzpnsZUAz1cIE@k8>!bojcY{(Sdzrtsl5y^U%#gI@bZ+k zu|Z2K5geDC&!!Qy7v9%^i6?=p=y$#z9*&zjZhxqVjn`Jf(bh6GwWStQ7qufdtK0-q z-vbw9k1Z@vA?~XJINOSWZpP2#(HMJ1VG5zj)QK|9h zo@NXRz=G^8w;R6r>W(fMkQ;Dw>M{K*p$ z%1&b|^*x6m@E>t&s?o%$(9T!G-YjEo$S0&0*4Fwns3mQRk&3>rAB`MP)0f(!b!bFK zy&WE(Z86M4EFd}CT1ztYdFVN_K|4M=O)W`lHP?9L2=S;dQ7*==So*B=>g^Us zTeg^!v+!wb-RhO38OE68c`S*OlD#D*gi~lYD~`J3;j$Yn?EVFUXp=xTu*#IDh9oZB z?ucx6n_Mr0l+8?4U$nbot=$xGJNhkP3cfP1WAip8Ze?lAC4{%^+x+QR2 zs3w_9$8O#NZM=}ihjfNf1$MYxtw_`#f;uCuzcL)`mnC00J2)@^$iGFBc+E=OhrhRG z!?>xKpegJ}!hBz@KlwPr@IF{|mgUk+UvHf0jwz$_!XPE+)tDM&1iq5&^c=^*HB3rt zvi=AC$MSsCObjWd@oj4-)-PD6g_%v@u$r0e1oA4)Lz)5z7$44LcswTjjG1L4Irq?T zZVd9GvBI6kaN_c%sMeH6(O^FYBe(I4N*n4;)UR(P{J6Vca-X^QOr{@)m-roGqy}w& z$$Xorfc<2LMK1AdC zPfptpdD~elprFn#%)8i=CH0mfetvmEwOfyT$4S7+-N%+FTYq?c?oyt=vCdDJQ}K`2 z`3*hsAJI*(eVl!9Guu#^ny(TAJIxP2+-Baq(aJSA$ltF_LEC7pJ*CHV`s(p;;bWlQ z&RWBW*@t_O8ERAjm7ensgpOGHp#@XOKRE59SFOOei)Tymr^;}YyWz9?whl!>y2H=* zd3mH>+wSLV8&suKfRDD_E?RelKX>)IonP>G1w?zqzra)^W&*u#gV*3~uJ`df`ybuA zxZSiiU5TYaXG_1E?94S~zerJnEIe=L8oy(8;dM#Kf=MVZqTUG!Qf?f$OM>5cEr7V5 zW;o{a3$)UW*GOmVe-ysC2#b<56~5~qbBf_bDEG;>Ae5MULsxtz8HJCEH&)r}+Ofkk z@az52JW}+ZLw)f9FkL5%&T+Tmn>(pVfL+cQYcC8$`JAqA!?H%vuKKhEh1jL0+GK?j z6Z8unv+gbmcz9fni!YEsFay8fyBJF&9|qTJ>l?f#z;fetcFB222`-h{%iQsX2Cv_F za=CRFg)dM;RN9tzCRg+1fxgf7e)9I&?@w`g?hpetOEF-}AqnC5(7V+Z8D-p+x?!!( z4IZ8aX%i5|qiY2jigDj}T;Kjmue89_N*k(`H}I%WhhMYreq!Yq?1Zg6A^*50D6q6J zI^?RL)xt!5@8egDy=QUER!Bgr+?FHR1ssUB>p4iF>R0TQmcI%b#dw5($7g+kv~DVs zo>$5>SBf2(YgY0t;Y~}dFAY<|jb3hQne}*`W*9)W?SkhM#EtDkN8Wc4g5#Nq99F*#<7cY>)V zr6j=z0qDDFNXO*;x}_#6E>n-$mG-68gw|cqYHQU9(bzdH3K01#6GNOKqN^(KQF(AS zoK=|wK?S(DPCLL_@Ue)R#C8bRpY!!NVMTMsuyHcAL<}6i`|b~iTQXzVlEKUR{C~M| zCtLR&&qHN6J?>ut<|6HrVO)U5jJj&trl9{jGGKMmv1aSLq}g&2?bYrtDEV?x%&4X- z7%+1#oMBo$V9b5#(DN*IsMeJg2jv|)@!Ym1>mOK{-P&rv+ppRt9aw+_|Gr=KZC`=Q z!*L*MsD2_N6~R_V(>4pbRV!VH=Egr_7h}D0Qs;yR{QL24T576meRdn5@?^YlB1bq> zHe;Si8;TvE`<`7!2ov8%mU4+b2#+6kM}7#bw1J*!wB(&^#8jpz;eaR?8(B!WB#^zz zp94wn5=GV$^wy8%T_3#LHFC;&+)LUmB-kvD5;<><&uZBP4}04Nu7A&QBv?Da(qcTb_0Z zJP4DtU%Yy9o-h%5_xk^GW4CoXJu$Ydjh*vd<}7S=ZY0{G>$aoP$W1f)k2ZVEOL3ze zW8P`+T%?Ppwih;yH24`sLlj!hR7?7JL%`gJm)jHykKrXE!a&AVVXkL%eiy!UIrQb9JTS^l+$Sz~Ll9be}@L4#RgJX4zm6EA40*N;DWoV0_mr zW1;WYiNi2Ess$iNl_gX?@aFYNFT-^=MCdVY&|nY+J?#VvK_oh6_dESB5 z(gt`ATMak*u#Dy2B5SiAA;&K$j((i$dGF*#LIIr;aJ9i7+i9LTQ774ZwKeM4FSTd~ zuD!fGbAQ-jp6Fj?c4(R(?OCvB?myOzGVmK*)^EftRG-Ot+mAZwuzoON=G-`N*xGHy z`FlYsB|~G%5n=CHy+&X;&zI5H^wA+dxHVbt=LG#BS)=#?j}uL?rXg1m#8ngb>Rs5h zGFEIRmH84yVZpy)!LU^qnnf@JniItAS@LsQD^nCnyWE28 z$aU|J4;ZHwtuK}IK(Q3Dtq}q_urHCnm~ZV<0*IvGLFxkmKYSy41|*(z)9%I{y)WYb zG`T`rBud=*@Q**PBr@Mg$j6ce&8)XHiU3VW+Eeg00R`T7wdmKky*}GLn;mylt;kpUWrJd`(@8?9WM2()^wQ2-W_@kwd6b(&dIit zM&Dl8PVID0SX2iSLIoYj@kU<0z6T(Rhg3a->(w`9LylJN->t4CW2kuEpB+`-y^i17 zzcO(7^Pw8%Bj zwE*`FVl9$%Mq9!G>1ugU-}RxA`g&b=!0EZiqD@N;(Q0V+E%;aS?ikP0M5JIA^}lU&(iJm?kM2eFtjm4wCM9w#U_I$1JjPnO&5QGI^|Bb7 zEFEb*mzDhVAe*A-p*yY0T!3@2WsVY)U5tzrb@QVVorVd|Mm~S;;w(kb%rp)=i6jR1 zXppf1>a#MlqCG60+a+{B1Pr8hltKqK;oB_0G|C1PIPmSXSYLR~T&q*3ir_(5LQPqd$LKjUy*@CXkUkXy%J{u0Zt}8tDoU1ooCF{5z)ep zRDk~v30PV*UoF&-Ah5N+`~|3?xGuzQWK=d>CVvS_N5!foI~VmxgCIwSmc7e$#I=;? zxZIfsMHCAd^!@41mJZ5sG+{3+urKpW`!O5nvUfKc+VOZ~b23?{{6P%r1Bf|_$zs(< zb1r*wZksR+sJ-@G8BurE2CBEwYy$KRp3E%ie^IKCilVAX?&=^LtBg6ILBM@AZqFZ? zzLJU6qG!JZRzGQh5i+Le7m9;1srl)iEIEI%w0%Y7ZWZ21Mrn}Hh-E~F$G@LzT7S!O z`HptH`X-vRFQIHQ?`7K0qE3A7Xy1y(RU9oSbs4lq32!MzhlG~-elHI{GphS(#r0OD z_~KfLhAiie0bVOdeXpAZ$i<`G`m%*plG}Yt4<2ls*2@2$a27*niCiC(QjcPWGJ_%* zeFM6w#m#?a0GP9&2w?)XwHQi+8P=E!A{}FZ#&Bz6A)v9U!w1%`(0gwLkOLfKNf2B~ z^7z2JpDvr5l3|xs<$RVji|E8UZ>6+r#k?+K=k0bOjji>npw5eg(H}~S`yzuLQ4Rq^ zl`Y-UcOzlWPutI+z}&DnHY#~#n3808r)t^@oW0L%b>H(~bR;fMx1K!Jc3<&EOf(Qj9P$4cc(d~SOtr=tiQ`c zx~?*&sv;E8t+(&;>s3)tY)^dfivO`Ci*_FyFRI3GG8jmA|Ccx&16iNNH~Ef}RVNCL z#C{=H@{@bRIuu`OS)Imp)2nP=$on)NP@voV7zUtm*{DBbBxtCKJdMnDZ|B*#^XP4M zNAei>A1_tAoq~&X(8@CaWnqU8izG>(RCmyECC(xFn=k?^wbp}29EY{}$m7T%1doH~ z@IR_@6NU;W8EE?H*SYhRN!HT^pBOJdnxhn^&W%{s*HcR3Rf47}{_T@d=#r`E_Izw7 zcp2~EYu}5E>VCFE$FEs1&%#Al>0rL$Thrt)Gga)So%X~9h`*IOkCw}@nvVS;B!AN= zKXpItxVy!MVr0sujbCt^Ly8Eh9P_yB8 z`**}Ht4#;q)!ZG>bnpc(leZ74!ZQJ0p_h)fxpgrF{*F8=i~(f^oobzy7kTq31R=X3 zWpr@X5`rF+07Rg#og5aBW4%LOL-kAe6q^OZ%&?&OMMNB;=(t5T?S@-RFmqVli%#eY z-+R4}8ae8o69MK3IPte(zNj?C7#nR-M>ndPj$}MH^bgv8z>PQzr%8~aYZ1+L?`8RS zm~&P?_Q8eS3FL59XP6$gI&Vd&9gg3qh48kh6bjJQp@l=y%ThSPwyAwO$r#KL6ou>< z8>GPmtZ=E+)Iz5=)0&r^;WzA+5YA`N2_B0de)8BkNsp@LMVw6P1D4}PKVhWf#kOqG zpIB9!gMRQ1q`38Z4Pi>10Y-YxnQj7U2~NAi#A$O5;@?#Sif#5wZhrj;7ad{FO_v6qznhb@n2*rqby+6quhH@4JTRa&Hew3%rXXd@M2Q4qn-f)0^Vhph0QS9fXw!xQ8D@4!>a1*FK{(^O7xsGj&a zu_0h6Ekg_*atk|p0fGY`X_zw5F{dB`L>H;tkK1NwQ z7B?~J&&Dkj5y-E3upTZOK8e$bpgUA-Y{!tNo6WZZv-FJZBH07cxel6TWLCE3j?nFpY)4jh<+*1w^I_@L_dv+Z$G$ONJB9 zbU(aSdZ{6lcS`$O@hgd2luGP8Xvk{4WmAXFI3sZn|5*uHJC=3#pX5)mzJ8zQ2T>99 zZ(TxsX`z3X^vVIAvLh*2MlQ<7e>DpZf~ko;MYBIP9p?<*H}gfS{p>+Bk;M#^;9g-h z1MPICzhxJDWhB3xAYO6TUkCv;{7*qxFwk9Q%oFm4CVV*Xy-2xHP3#_k8E8TR@-g}@ zZpbVAK9!Zn@s~Fl49|*(1C1TUdo`~owfJ5_ZU)g_#=PG})c0j_`>%cPN9MZxIm8LS zWHy@LyiKdCxNkm&s`MDspdf||>-$U|g561ZTGQ-mbKhQZ_zTe{9g-rVo8rV5<`2=S zgWbhi?5^Y0d;(!l;zuu}? zGOa$hAP043QTz1-b7vE4%Wql?xkod6@NH*y;D)jP5tu%qUNCiUX5A=Y1A~}1kA3(x z?6vv|PSViOmZ=kwXsGe5HaNc>)tx>u-@j)&4xu7WK?wYs_d`n7 z6W%9(ENG#Ov|PaJ1M`7!vs=ruWFSBT$=%t4eZSAb+V7P|0x{n)r<0Sz#{OpjGU)O} z`jc(2ubaO&zR%|L`SyF9u7iYS0ib%|jw@qx(`{u{m$JK<;LYliO&d}B{j}jntTHIj zXDdZ(Sl)}*uG-a<^e_T{WHf`Vkp+&KRY(gjt1J~j!CMZk|=mMYfg zVWH&UV;wFkM0CT}1e@9HOv*<=0Hu2@>uISrss+3IDsMr*U(!?B5GQbt(htiC{iD|z99JbJdmY=7Y2hJ9$kO~g?6 zOT>8b?(4nUS-^D6S;>V5{?>}GxSb@$kH{01W9E|s~yp6 zF=|DWU~EEM==&);xkZ24KU+K7dZko^7jv)_d^lVyq222J+0u069d~%QcYfdX-jM46?hfnlJm4*>Lk>?WDpEcc zD6zI!2dN=%YCgz|M0M^Aypf|ygK)*EAebSpFQT1)IWwc`Vl48V?OX;z^eQ^Ju0ue11I=@=bY^(+T)KDSaAidq#lKVGaO#kBNQx;$cl(6k?-H6^i$q?sq?l=`Mbcc|6#9axW85sSw ze-v%+Ty7|{IIJx=kSrLHK68x`>%l9kEOlKbM8Efs?+>=nHy6W62{o_{pK@*0C$<(N z=eDk#2!Q%Ky>vF=2yv2cmGMck>fx}9vx<|*_yGbdioczI={nD9|Hz6)CH-vVZ_k?) zDasaEWahuX7_y%txh-&UA6UW$XILq6i6euwn5xE&F@bR-MdBABt& z%_+I=euJl3A?`570z+Cp`a1GcH}2~c)2+}79*22Uv^kgstCpD+x)Y6k(d10Q&Fni6 zmZ!>~bcmbnn>bfYt(WKXD)(nBrJL1`+eqAeL1j^5C zjYtAnfke=Br?zu(QUYQ3*Uv5bx>1?3+%^y?d8`W!2NYry5kmQ zFR`c{f-AAb*yKMGei2JAf}P3}Vu=cy(z>13V+iWYV5Uif&T9uZ{(znQ0Cgt2b7j!a zY-!DWOrsy`YEkn+TMQVZG^n-(>4GeAq?SQ|TyFT4=%xz#5G$8Ua6sVy)@C;t$YTU-Ssogm~ z!_E0xK2A!m z3OCTRuCLxcvNG{cmjrWb=-%3NG1o!5*^A@AH84kT*Q2Qe0oL7`t^+fzwwr>>3E4L3 zWA^xuZV#HpCQZsa)Ada(j=%~fI<>SPLMj>Uk_}#^=rWPjFHF5HsatD3c$29-AAQ$9 zeuKhCUa5HH`6TGr*oKs)hFUuu{}8N3E{hiPvY{UYHg17kv?3^ey_o(a*l992Y)#ka zBgLiTmYy@O?Bg?y&Iqru>2=o8F?C%TKzV&y%rlLi5Bhl?i)gizZvLQdhJ#-aQ$znP zMwClVC`w6H&t8x%?gk!XTxSVF@Q*$T$1d2xo3=hVTYjctF~E8CxQ}nn`AVD#QWDl| zGb`rvbo5#$^K=XwX!+`%_>r%PO@?0(j)_0mr7(KO?0Rquu5(na`tz8l5(4HDuJACTtL$onfc>`|};M>*$l* zV%c_P{LcpD* zYnIT@b7!m`9^>MY*E^va1@Z;@SODAJ5mzWx^ls&#l;b?%v-+Vp*%e{3kFgBrwgj7Q zN)GxJsuDgJis(kK2uZj#zvblJmHH@*nd{goINr!>3~g#-_nMxyQV%G7Dj(eQ-!(#2 zN6Y*ToCJ^gQ;VIpSGC-Cu(bd6BZ#Y3Kp~D0G!61)L6;IafmfslJxRPq2dc=RrURs% z;bzz}$9_KeEM^zEEp5PY&^4O*j8KOhBW<4%jRy=2!j@)(5C4)tx{Rw&l1pi!!akQX&-_Zd5T{p_WMNI-A%^y)tco6k#ulhz6<$0#*vRJ zIaB?SNB?xr)D^<}EQ&f5~LD58m%+^7z`U zfs>mFSU$xm?Wc%ijcFIrD)=+LZ+L9zp#bpYd2VzqdAZg?@U=`@H?VEKfjN{Wm2n|dhdUqS0xkV zOk;d~w<47#%;1fq{mT%LYKsLll9oEVQP5jay1{eKSWwa1ZB&GpnRiLk2G+f0mi)T} za$d}M$s=!M7arF%FuwaaZ2q+xvL`cCu(&~$SmDZ8Wdq#|SMV7ZS8VZmdorEDIcB-v zsn6WI$x4~xaA&=$Pqf854lB0}R@UqpyiNu~)S)u3YjzpvN-_2SH3#7foWT@a2C=h42Z{BNZ}?zv?++$m+Ff`(5pmJdU#x z(P)2SIKp97j{mUIC?$PhOtq}QdaD^QFQy9r(J%RpLmv&3e;y&+($xTd*EvxK;b(%S zJNA$4bn0vtbG|wI=^TV->Jx~u7&s!B{1_u9@g8TE;S|J%g;@HewK`^U_ctKYnIEYB zZ3usScHCnK^|XuPIAIX8QZXGt6cBf8R(=?NSuC3!N&X184b{c#^aip0)w+B$@8ZB4<;0@O=mS)%N zW;0>VFwEIU7h^~wo$MY}2Bd=d#U0e%-qsqjd>KgCrt#%rDX02l4APw*-2EQBr7H0+ zVUXd)XZ)#252#g$e8uAmdsA{9X0GC4P8P0aeJJhwi?T9~`{88!1lcOWbG-GX`6<+B zT{iYf8gbYOUTuyKg}*An#j6ZBdt@*}0a}^#S3MyJlhONiv6GNc(i@qy_StrxcT=Ru z4YSH;fNj~ejLp;zUQ(56VCy$yeU1;6iQg=;8?(8>n)M-oUN@)T0i8knD(~FW)V0P& zyisOxjb=4`q&ZH->ve<_tWvlL+~{db?)WFfx{ywgM9lugXCk#vZ+!_@B&41rF+Tcj z7Xa%Tj@j;EVj~5muUyk=dNNh2pI)SkeaO1`ef{AC4En@@HT7ILJf(0AyW2ed2_RO~q_{KWIjHZ6HUJ zZ^Z|va0q?3=;N&1x344l#FC|}zk>Z=9_@W-Oq)&NvSK5SIk|ai!rsDYJc$yiYo3HH ziH!Yb=nB;eCkuWCV9&JvnH}jk&UZou-ix1~5BK?{LEFd0x?e5_t)yFiy>t0p(TEm`H9H%pG&sNK z*CDo~!Ky?JOq+$H73dhbU&Oa`s`2AmX1yTx#(?(4<66*(t4wW(9{bUr;!YmCgas=E znIJayY_bVf*n8$o3YGS%*|=9}$Cn}~^xIUn_ZQv?w3yG8Ql0s@$V$t>nLeRZ%bHn# zA5xoc?eQ=-cdaV^p!D8|Zza!glQn_0J%-AcWsVmRC|ukCtm)i|eZYX$DMlu`N7rlz zUY#?N;a?`=TkYD=Z%?XeDKTvn;Oqu_rtMESmdhDQ+V$%K%^gn=;?*&-_2Zk4^>B;P z;Wx+bxVVygJO+(!f{Xmu7Qq;Tws>ecqGrFP#R8w_`ltUQsybUza(D4%!h7>R1FVfJ zmZ>6Org!HV9r-vV-q`bFbF7EXCOZ{BFVkQ!U|+9?A8%1E$AbUa7ZAd}m+t9B^uGu_ zdJFe?pqf#^xU`40U&kfXSJ^t02osw`s3OQmq>t_3O;@w#&ynlwZwdkyXIa(11JT^& ztnlk77?LJ_UoYdbXBndZP7sInt7i?78>=yOXT=0x?whZf2qhs7?ykHv0w6fAbg_F0 zX8R>w&!03_-4_xEw5L?;Uj4FMb#=L4P{w)$HPpJDw)XF|aoaWa-ZZ>^);0dSmwWMV z50v|t8zqIjDZTyEo_2WL*U(dcMGQyHS_$a_2#hMt@X-X;DdgBva%vKX4oi*P)l~z_*@TZm%)o)iExiBEw0?+P<32%Ulqf-xB+H-) zJuTY_l1K%I3h zjLEA)09|=|iCJJ@S?jmcO)m|HoAguAde+_KVizThWZF}Veq|YVY*CV8rlSeFkjj%X zcF}?vEDJO4tFe37pY7(q9%0(I$N<><-z{nrpjjqDTppc*!q+ywM~Wx-i>B(&ZVV~Z z_s)oQBoBSkWZ^UPVm$q@B{4m?(;!fOQr;MMQCWbpi`nP1lXDMI~ z5dJ~PhZk)m{@mR1EEU<5MM*tmHy!*4Dn{q|QhP0NQWEq)em@424A))v`RyfRZH1dh zUhsV$g$Kyt0#<*{Vgs+S!Btqm!AU$8F5#Roci?;KOxGZjIO)o zYy!i%v^f~1>m-=QI(Fqek}baS-G61{8S(S5L#9HCqs+W7=;m7A!(dScqM)}!9P9%L z8E?1A(7LZ$)QdJ0P)jiML?r~b^*|wIVRs(%v6N!n9=}VL;$7#lormKC)4;!&<7GQjmmzFgToT zGY!T(o)kL{F9H`iX1DQv`{+^NO?4_V{VPQ{onD=m^%QCYB zR?z*=YxACn23Ha+S1B=~asiwnT@fM#-n?0;85V#{Hg;Sq^8kG(g__a;!kZ!dy}qru ztRFuB()a$ycPnW6_iIW!E3IT_(ilIWfK)?Grv9eAllTqqM%9v#b|^o^e2A;sS8xhw z=7d#Mi{GyGe&?&CXo4K6!t zw%@Nc-<0v0jWDa9wje@c2l+xt{*}_+7wk`LcXehNjHl6&Ew)PAUT;_+=MI0q)UUTS zaHxJ|K#O(U4vUB*hxk#s=Q;XD3jphtU!Vw%Om}`q$+zSqLX254w3W#Y`$rL<$HY*^ zB+md8A(O7>;(03HC*`X^|E6~`r%aL^?cX5Cz>!3B@YFR6MGi!xD* z+Mi@kTAYJajfJ#Zk|@2q+seX|`zunFGcGYm0WP!azirtyI=5{ksx%MBKxYZucy;q$ z*}ci-PcPQl!s^noFZ}+5S#mSu@|Mnv(xX8dKR)+~XC?hZQOx_n_C1F)e@SaRyT9XP6j*f+Mb*5LoTJ?39MOuI&U-;q z6P_XOJ1jsih<)S3RryIX=%7yO-1PM9jd8(vzpBVign4q%Vr7d%aHpLLI{l9Ig|h+L zaJD~bfAm;QPPBy0^s5FV;SK<+G%M(UPL=Z=3XpFw3z1YFo%buJ58846jwrhoo zPLNkc5)kx|bZzn%|8YkZ1t3!ISZy)oy49jvpVCnua}hr6eY3`#YSPtha2#n7NEV{> zrc3li!@|w&&lG5UY6A^rA2F6nU9rwnt#&HE~W25#1uF>*$u8IeVap6 zzXWd?oaB3UGc*K5&urA4u$U6{vTL@;*4aGYD{+nsP=(C}V6Sbp_ zhd1&Tmt9wnDXZuCd5#fRPp5el#|t@v0RaCsvrW)nZJvit*;PDAWJ>vY*L5d~nQim> zInI#VV95pOw(R7%8;sObLVm0GconmZh4R5K2OoHTxb@6^qhU zn)d-}X|Z@?y5GlxG+b=}zsO^MT>|y?HvERVcMKDR;A8liS8^_KEjMSeZL&I+YBI!$ z&{PqV9npkw@N(IW_o(}^Pw3B%bsXQ3tOc1=AZCApk*V`?9WE+}V&<&bDOPRsNDR^L zhM+r&yS;{yaqVKaijHGDcl|`(b@g>mZI~z9i6!)koLiiF{AV~fZ}Dme%%tgxz!Md5 zews0lBIsgOyB1(qW=^ ztFJgB_*3-(i&GJ?nxZQPxLIl?YhIV*6XK4!c3q6(adKJLJ$hO ztT^z!irD}CL&zO>qZPW0D?_9j&E6SU zEfAwAy0)B`uGzQJ3$~Ev`kO-k4!qxq`o0@(Ihq3*Q_d$5AG>5xDKwD$$ygTkA`QP+ zC?ZfE^-@sx^i_z;CcVpFafxMvI}X&Iu^OA6Xab^-Nu&r|zkm{?fUP@tOcRb_S#4+~n`Yr9*aT`aGu zkl6OVx4h2qz$dNZ$`xqi{iQwKDYdf1I}lM#v3Y?_Yv{7u$?4_!@sq65PEVM%AJrb% z6b_IEofV;-n@+6_sUx#)*N_(%aDeSI%y;L3F)ja^l35p^dU(z)p9R+uWV!t~u z!GNJtoh+6%VIBO022GW3oEWmzDLI`CIkMnX<2-e7YE!c3Gn@jvZ(y!y_QXlEW|xh=wcwuuDpbgnTX|YK)dNj% z3u5)XK#``SQ75RX8hBTY{Lg~>19UOjhAg6;*rxE*Zl#2VJ?>6XK? z&8{?O@OT*)qoQgR6~*fm!|lx3sJk%S!1FV*pWshuTsoRlo+!z;A&FkBU;MX-b+T&~ zf8W2~*E-7R8DKdZ9|9bYN+mpx7?U}~`nQ>s6DV}nUxZur87=O}{)N#c6vPv%%C+K` z7#8C@9OWla?rx`{2pB63rx>M3;TH6p1(V2+64YllfNSx-&DV^NFuao6ROqnoqIRB0)Phc&{arQ=|ip5?6@JC>ZdS!vpZTh#s^LS;En_?`&5t(Z|7=66?3 z{VZ=BA5&_Wqg^U9?t(oR0y{Tu`++w!u|+ROf&byhI-y~YEN`u(L3bDRBJa;j3{U&E zQAd>i8OsBx0H5sK;my|-GaS4{4}Y~98?SA(zfO*k6*V%TO;no z;P9$kuGKgcglp0LFoq@7Vh9z&v{DiL6rZFPLh-H{>$$V>KlOvSCb!35CoIm%m}Csj zZm0;8s)h6!6c&}rjfP@+lZ@G*I#NKtnj1U!+z8JOC!1s(ckjdvqk1y>ig-h#5Imf? z6pymVA>V1u;|}WGRy1PGz{)Y2x!x(Lb)kx;n4h)%P+TJ`#%74K#afDC1S~HGA9io2kE2+4)nC0C}rX+vo~}DfGx#n z4C5#}G)l9;S{!+|1C%Gzgd9Az`?t-G0kX6eyXqQgyyCzcW<#hcN}I=C!Z%j$km?PD z1%T;Wo#oN?FlY)dWl4BuU{-=k()EEMxj!aPLj0b2E&7r#p?{zs$^!#XtH(^sD&3ru zWFQIC-smii0iY|MGHj%V$Lu%>zHrHp;r8EM0V|h3PZNQ7w0%ezKwJc9%}{Vr&42V@ z!`k(GY0D{?S7yud?AA2r`m~~AR-%<&{c4fYGBu;9GdB(K1+=J z&LRUz1nz3qObp&L*Bn#~t0kGep;l|jJrJ`Y`-Te?-(R_cbsS~N=?{hNSjSQlwJH&5 zb)QPDbHr0vHR?`wp0*eK%dCHg8!rC|tbb(Gv zpI?v$fM$Wf=${V&PX73>#VJ3m^7f-f^}xY14~D;7e*+77P=W38gW{nz29dJ308}cB z=FwT1g1BAQwlK{+e3E<4)8?Vlj!edpWUy5l4I}8hu6$k85)()^t54v(va0@4?avDM zRDp__PbT{Wd--Jy!A3c*`UGgKn981H6biZA3@V0dLgS@MqSHk(wsa#8Z_VKGmopqQ z(}_cw|e|13(yNa_TDrl`QJ9p|b%EBdu(X zJEQXpK^rWWB_XUb*^?SOeSZZ4oi@rk)Tw9;EKI-=os(-nk^u0Q6HbQHKKK#%{l9-* z2saLi;YKizvMwRV0IK4-RO`AA0JrDn&K@CONMI3on@ivgp-||J2Y@jressP#=X5kB zu_k=iohHNRQ6pf^eRCPr>wPe)SmS6sB-2%DqO7eaKkfvyF9yyKcveD=I7MjJHrY{n zVfJ?SkU-eD0F(woO--$@jxu7jEaE1mq-%rMrsnk}=)R-|BkC+!=%P$qlds>Gya&o9 zi7O{vW^Q9Gf^wCpUZq}-pTEJGKrOIRyAutzxePV=X+e%L51ar%F$)~{3E3o`Dz=hk zB`C!ZN-jh!+(E&|zI^lCly%4#8w9q&4Wbk#7AOspMdp$pY^~S z-bC=`N0LfFrpAR0y|M08IGbvDX%IMR=n?;5=tHiwU-KlrAJl8X*`>cjXrpXTxhl^ zy+JQ6w9A z3Pww_8QmXRwWI={IFl2^Y(hFX%NYt)m4}Tvnk6}vDpYZT7yufh`^w_z9~^|iO&g)= zpfVo{0PytSj@as`RWkr!xEzjBid_n^oi4Qh^aI`kfBD&^JnfD18LaJvlEB^wN*iLJ zTfW0k-0TZ;XK$Ah_{iZ7z^e!dMsElJj5+cAjwtj8ks8V`QK`ZpK%OFEkisN*iD(O+%TrWwvRAZ zV8r)pbQBsXKn!|PQBD}>)@0xF8v<=u{+zBkK%cpUU|X(A*5YPh5;HcvwrN{Mp3Xmfsh}px(CIzUP=R z*pVibm5@{{{F86)}P{bDLl z||!j`oRzi|LC>d14y=ogFMqu~=EG^cn- z#~pnvTzAXOdY|oJBM5Jt7mysUt)k2(Nn`{`KaP>U?NxCFszMu^2_2JlxY&BQILX!8 z+Kg(fv5YqfAn5>}_L)_6WR5!lDV-;epDuKASs_~jBKUlGXojLKg9b~aP-v4ayd^oH zv~f*w*>qdx08-s`XyNc9U%nz-4DmjS9X+fN@V!|x1)eO)9eUKBeS1gup(6P}pro}D zG{iwP#hWa>PR9zqb;Z@N=z)7+!Q&4b77}xUg>_*CU>X}!lVKdxtOZed+1xvKPMQDd zAYj;}F5rLP0@&`Y=Uxh4{sIaxW7Swk2OPTp;c(;ZTlKlez$Wk^kW4O=!L|hRQhvC> z`l3cPnSngzhm!^jYANslIXm9BM)?&0xCA_I6tWMn)YgRy0OVqK`R7`zy0`$$A|IV4 zNP>tN;0slIv8JsCDcpq^L?mHGG8W=xyE2g?+VHhC6W1cd?;=l~j|Ew>dqu0@yI1`WJb23uu=I(4NGfZOL>D{%0;~kA2w)s6q2aIHm`W||dvV^KQ?@|( z(2|a?uFo>q$A$>xwv=kt7yty0<5alTm+I$rvf*L z;K%-QO%i!*d6vLztJP#61|68$ETjZi1E=i@!V2czd^|L6KrYmP*A*QpsG*}0KEbLrltyk0>l4z)dc`# zHxIqR7Qj*G&J$1jpr9T>uIRypu@hm;#BuQOBmdxqD9oNQ`F^V~sVXxY8HH-70ngsf zYv%cNfJar@QIM^u*?YDKJY?4z9)pTwWPnXAQmU{kb|kbfG`KF@VB>5Bme=kAn3%|; z>ZH7m$Ab4|2KX|AcSg6MotDg_E;;VE=-1qPUXn0h&rrnoh^@;6B+_y~?M?+cIB6`5 zVj6VMYucJ@rgqIf3^h3jg_;F1N=|2%)}u1*YqI6rOP2SsJ0?2;5p0MI#IY$?fvP)= zLZ;CZcYuq2@Kd<)zkdsBUw#pyoH%!cJp&A0K~=anHQ}lZR^&_ozJ^LISSJ8rpHvng zXkr1l;sF1905IyvbC(BUI0;jEXd>>s^R6@yQxSm_gA$A?lpW)@IA3mCfXo!sNejo8 zE6>aj_`b|D0Kr?{q=ki*B(_oaY=TI()83WN^j&TqoGc8Kekb!tMgE^-G zV)E29AK;FA>l%GF@qOY`pB*AV>B zVg;lDz-IPG|7!rS-H{*2iF>LQI7+IKZw06&==xWj}DAT0~G&bG?wNJj#0d?_N zsc$n34%!Qw(0|6~PKvL zGX}E*s%pKe#v&D;*z4d!;DZ-l1lL^pJ@GCo4Zwqhpcn*XaEXsKSP5Q!`QbYcF$6nE zxdXO309#C8D3yV)4*-lf{Qcv_16{>~D6s4?2YXE06V~qdQ1k7 zh&oFKhH!L}O29@C_q)6J?6Nrjn+5q|N^eI7p+jlcUZ?*}t)``Zt57JS4y=4s&)zh5 zmC39Yl4&xlz*5XN=yF?Z-G*_olA;{L#UB?d#Z5&jdLK95)C@x;zGl7`zk!pHw0uPf zs#xH;V!Nd08c1;EC!a}=22J}uo({-SrocgBO4lR-fUFWnPeD!`iwng}jqN2|7;fw4 zlp?+dyf)7Oax)%+fWpr+2>=Jb?d@>d$NmNW^q=45xW6#{aU!;QPXQG$Rmcr7CoTIeXDG3o#Uu$KjgDZf7&LJZ)I0f1qLzW1Pf!Jmhhj%F`vqF zDbC26QHXi|sBdGi7aS2qX;F1FfYY(>I1`RK?M%4#XFn9b%TYI=7s;LroC;h)3swMZ z$ruZULqRI_XIIR-^H@Xsr`-TsEFj3J3>lKlW;v7nG@_88ySWDu_CbKDXOI&!VR!|ZTF3jhTW z`ws%DUw{OiSi4O3xB!4#fg@|@o2q8RYqpg>t4Oz>(SzS?;DDUq^quMng!GZi}s>u%-plbZrzLAcI7IJn=V?yY)2duD!q~-a3bk zYz_cIV2KW_UUfbrv#1DD$rZ;GXw96YW)T|f)i@7u`k_a_O;`NPCuK(xd+I|v6m}>JOCp6QcM;;FM zKKQVHKqI1!&@R@84FEWh*KUoLH!=k!5xHGw2nKbPoyvnV&wEiXj`YIL4&rf?nTj;{&|clTLD0gB=ek9)y>C(8)dZ)Q#n3{y;PW4d^%;hG56G? zS&wz=DEQS{P5Rs1vW_XTM683`-egCi49e*tsm-GMVS;T(1?cct+`z@reRW?Z9|FDm z&K}yoGT5)@CYr8`DcDTkHRz0yX#hwOeWpQMaR$`&_;WtqyFc}5n7GqqxbrVp%haDI zdjUfV_66uBmCBR}AVy$$%)U}};mSv5pXw0!^zX9Vg0wsE#sR>vL*M;f&x^i<{t-Ut zq7c~q4>|xIc<7NhOAxJxVh$~U%~n%4S14GEb+Whsnq>%L%VNOFbEk%al4ih{MWuMY z?nLAuUX)tUjgQTANlY#}Tquf)8sb(WHkm!{Kc{hBl~RHnGcCN$`TpH$!nXEq!_BB! ztqAOauL#Xv?%f0x8k}JnklHpqzO z(QoRum{pJ%01U%0X>s85)Wu0f_SvguzeSWx*($+K@%-81LQM0XYz6+ZwdifH`tC8Hw2lo<0rk>>;NHbB#Hj*7`XbSt1^IpxW2cxh?QHJxp zyJi3oKLegngAGV^%E{;3B#V!%rD)K6$ZH@h0M3#3Isl-^)(E}}C!;O`$#6+5+UGRe z5hOS$8FK;XxQ1d(6ms~)}U1BU+}q~Za#SU^^# z;2R$U=sxI-*`8lGh6-_nM(r6n3U-(@85S;Dq|Z6d+mM)`qsSscIbMq*%CbFF7js~b zxg7hYIPuJ}THLHNi~?Y`X*OA8AbRGW!-rR7Ag*41WnDOP=W433Y_LfaRr1KNcDjEW z>FqTx@~j1{*>qKmqaMhCA5kJ*$mbBgrf|LLWubv6r5F!p#b>WTwCwPGQ8+N-o)sWd zm2_-E4_Mb8J@YQE@#oZC-JNozRAHYpn217%E`W;K$61)v;1&rc>`tTurM`Yws`}B* zLYxekawlL60AKvCpTg>;%VGY!`=w0gcq%ZS1KX_Y;@M+rv|80vZg|X11LgZyKYG{s zmMlQva09XkLz-0uzCKw10RT&dM+LNOpCo%9TfZI z6WUVw+F6AhNe=mt2SEaJxi_S^B*GT*+`!_p01!N=NXXIypB7+u3ehzc7y+i)Sn%%5 z&N;J>pZeNU3l~#dxNxH=*|<^@0*<~r`tl46F(Z!&5PE75#z}-A)f1z~;vyI#%V_T= zQ`=-ewgEtv35{SyetQ(k_U6DI8&PaP0&HBAVMIUHF-&%H4mhLx3INg?JAKZgB$idC zy|&~`W+dOEIDsBSVgUcwuDA*oKk^VPdF(N&^2^C-$t;nm{cA*q3q(yH>2m7LeS>$e zdhG5`H~=8BWCp^F>cD1Ifv*n$bRPK5L1Er^F#6_T?4%up={XFRFJ~fTUtXi?yE+ZJ&^7vgPP#ch3%Bw7v_;~(o?+v2jCl=A z9)6qx9TFIEM`6sotJw|oGtDvRB8MN1Iu9KA{T^CJ<$=wPMj*3TsK)W1ECyoi7f5OB zMgZuN8KJ?9z5-8^ftUb*-~Y~a*TdYuUI#Bd{hTcHL+ce2fZ`tlgsVtMDqPL5T1g1t z#=gOuS3h?57gB;=PYHj}MEeI8p>G-!*eU=p?BI8f66;_+qZ&^`-Fde?pno8MbsN_3 zLap_|sJ0r71h?hmt-iKSyR_>_cw;voYgwg*d11%Ez&kh)n3X4@uZo_ zK4CQ>5SRtX=i7C9jkQ#ia8H_b5^5Ks=~(c1pe2pUMy*a`riI@tESxM;S%H`~xh=wE zR^8z~aSX%PS}&I?GG}0lP@^e>v5|6B76X^t26{?wj1h6yAqNWO01~4v!DVsOEW>2e zbq84uL%ytG@N+`|09kxw9Eh|nS4_ajva`#yy6)17EZL}{29lVAEp+fHQZ?lnHTvip3F`+ZDpmS>iSRN=l{%}4w98aht*ex(EZa4% z%9CfA?rNWOJx56$3Z6sKc5 zEE?Mm06f7dtBA=gKEgT%r5Hwxp8)^%U%!Cc{_tDqUAG>)|ApJ@5h)1Xeh@?iQdF## zA~#vTvG&cKC*&q8_9DucGuPap)ej~OR(22etXN)}&a=~Z8>9R&+mGD@cV!UN z;#AX!R3Ew-{Wr^bZHt^h1>yi+jRt>mp-n`&_bQQHqQ8j*D=JNx78GUPmIpUm{b|*@ z%4M*2Gg(!@xd4D_{AKl9mLIJEAd7i74iw5~uDBjBRIaN+nI=sEfEl!NE!&2%VCLi| z$t{TYhm>3@&KE&k#Dvd@+$m2{mDj9YlN1;p)(8MQ?6y06`n#9F4L|?6So8hNGL&OR zAiT8Dt8)zif^e0u!IO0Y5&*uP()Q+`x+4qVvIgE*0O&m6^bZTI|Le%(low70-ecy$ z@buy(dZBjJ*1@ngzabSCw`}H^cTe|*$4o(#E5}^AO7lgrshzGMY&3rr<8GsgsN9EF z%l4zW04z;N{CS6-`G=ZU4ckPbNOVa;BG(X43m0Y>We(Ofe-V!iias3UUlN zDh^G@W&}yIffy3ii5{pi>}oE8QN?Ij9g2iRaTTg&racZg2+sevufVmJUJA8{`4UL` zV=n*&t}#=Au^`R@=vpT6bItnozg#!}!JiqLzHVszddd>8Spm%ez?l`;Iu^hI@0cY3 z;2Y{iAr;u30ss~+T%`Busjr33Vm!IW_v4quym?H#shWSXQef$ReV))#;U*&^edx)T zrE9>WMjB{p6moJ2W|Mt1E7GBMR&jj;y_-n$poYf)ojR5h22+!mwE^Y~denq**2Ev8 zm7x|kX9);gje@0km`70;z{G-^oaC#DWU|t78UQk^glrDKRLucRAaZpc`Vy4dGTDIQ zx&u{uT%&k^CJmKBuNr)kZiw6Mqw2#_zkU|`z4d4~^ZZZ1b(dd;>Yj^ys4_4Zm8q;DMhRrhiTTN%I4^+<;e0A-=UNfYW~MdASc0>j|0jov_=q z8L;rF#c`of@CvjGVX~D0rvrHnJ{P$MoaUo^t(Vj0cHHO!j-0J*BGMUvc;vWGOhav& zyuvK}FsB0BDi`Ad8!ld|QNMdYDK`{yWPmNSb(8RwX(1 zH4v#j00b80szGZL^TDazDznWjJps380p_r-g_=gKk#6<^V(}j zB0Z`4(G8$(ccB<6$OSNfZdlc%G=SABSAB2&;z$0R^7jJ+1nQQWfUL^E=#2${{ZE}Q zp2u`mkkT`HEc6T?11naq=97pgFgjXC=CZXDP!eMjLZ?h=4FC?RFrMV%OF!Ge1>k4} zR(yTf35eJ2Nz0-hNGn178>8-_tRZNe8pMx~N0o&Qe1kkk4 zhZu2-$gC$o3jhJY&u4Z5au$RehN>Ae28YxNtb)#+-Fo<`I`6wb_DLAG>twk9#=lXy zJBE03H1!AT0ezX_>LV*4LQB?*or%>iz5LbnOCG;HCG>%`2-2B=FarR>AppSEF9q(H zc`7FR$0(NCk>huurik?$c^C+C0gi%=T#Y50F(TuIGcA^#H&3|$cB-)KT7FIGZSnE( zh4^C8UAgHCLAamgsrP_$x zwPwV7{GrtoKwQ136bH2`(`6_`~f{Q3bv z$IMeYP)5|i1k{qFcia&|zY{jCX8j-;*P< zO3U_Jj_1*EiIVuNMvF2eUo4Q*f!Ku1JI!b8HOFhPneZyV9y zo@zYFicZHQ9d)TK&91{xo9_sk#7u+bz)>|H3d4F+4*x`1t}*aK1@ExCEiU0rQl_ID<*B&|R-ug3axMU% zLK*}BS+C(T$vGmQ%Laf#%m!2~4>m2xA(PzFUw@z zA;b=dUrY!>CsYRdNF&h0L`y?f+F=mL-ZP%6)HD1|B`o=(8c{uum9=~uz21)cwzBkVe)d|PaKt~z)%cvBv?f#qT0ZKLF&p!Ubg6o z^ZQpVd&cnl1Iynd0|3%ZLqj19d3^w&ZN^FGh=+9*js(XxV2qCMG;JoVT(vT;R;#Ur z;YBWfQTg~l^}masIqc{X3#YVsJ=eM$aR3#awVAL=$S6Kw6tE~kKn=>#?V8azl$|>_ zYu7R0gKmk*2BfDE<@0o1t`wcpnl5&kM1@|tKbt+*QRX|8G@;4B8>wO>11K0o^Fs>U z(ZZJ%a>Gc*<- z$$P{#l|J4jf4Uy-yZHuKz5Hd8OJv3Ja-Qs14S6bXNdZ8}Q-kI4pL_g)_mtMJSz!ou zItCDcy+Pi!ufji`KvM=1%DXnZD-6w#s5tXXq8AWStS{89S zsVB4kJ}&dMYfBZl$|}53$G|v;iw%fcYBB#!?pc&5GE!zVo{Ix;^`SKar7WsAu*qe) zx^mHI0*aqoN7MX%3;+?iXil1PP2lM!7d5S|%vNTKxwPwYXO$ik zZtWU&tt2xumN!R%M{A#gfTe-B1W^81^2ohsS2$o+GyMOWB_Nmv0!RS@I0}WpkqY!) zdkkR4NtcTIxxkYH5OJ~Wu*bfz;^mk1KH-{YpeO@?u_+#xvr@W@T7ml-1Vt5l*k-k< zMPSu{GDXPI?LK>UflPF}iQjN+8WkREPb?fk%}OP{x{TBv+>EKZLv4m44HpVFwF*l? z(9?22QfJB3Ta=aJ%McW%;LbTyjmnjwG*zh|Y$P5r8HoK^B?EVLodHP4G@4HR3E86X zbv;2s7$ zD5C~h_yjDGgX50KK1zMgbdReDM`>S|YoY>K9C;46&^MP9RXOFGSBy%=nD4GYZPMBK zdrsfE1AOcwcV`k|D&mc-eTLFe$ZpYaSw+X>oN;EvmsOsAMs@_Cv12gedpBB+&Eg}x zF5;=g$xpQ;+msCevfL>(N0Rn4+>`Bhoecka$&caBmtRKn5xktV93zi9V-;mwwO?2O z)d5M$64y&Cy#4wUQ<~ot`kJL6$W<8_rmTX<5eVFx0C2)Q@#7%%GVld=kKGA2tbZjg zFI~BiQf@X=Rz-7Z@(q>x=A>_`7DcYnr>~Uk<)j$ob1hiqU%P}$X073d68bZRC5WC?D}7trV*r=Lew z6+jtCj25Pl^yjhQW6fe(WVXPMYW#5d@kFbQ z3{r;*01VTqqQ1FJh0L8tJ&xwaz5jT`m zFQ8}aMDWC78SLZKSA>YS{&`wJwil{`VXiK4ojNSZ=hEe~V>Ko6}-DAjN3i6z+ zg~-V)hhjW(_d=M*JM!dH;h59Tf?Kb?3WxxJ+Ttj7M#kj?;X9RLvK|9EkXRpw0h;o~MjRh+UW(J>s{2wv|B zdcbis-l(j?beMQau7-}RT)c|%tJ2dgNyDkdh%bZyB4K`;46#kB^dw`AS)r!}a`GhI zYyfb@7!<`e@%=jrjnv|Hfe`cb$3&i4rn?%zkxmmPi8vfF3nRvXKtqC&^2M2(ARlK& z9H3@a9lFYnlf^=AIxv&JFRK%f8;h8HH8$-n0EVO?vf9x+-tq5wAMAg~VQ|-tHxd0e zuAKnt?7m|5D-icDET^hi3zc$JcLCxvLI7Ai`>&^`DgbL1mmo+52kVwJV6$mLTiF8m z|Lwg8oF!LvCwy+z3;p_aPfyTD0ttaYvOpjM3&;jb1eu`E#s-57GRau7(XN5Tu*QJ* zx7eT8Hco3}^L>uk#s(a~3_?g45J@0V07)p1MjB1*na;WUrK-An&pG$rx>c`kbx+V} z1g}ujJsn=Cs`EeTfBxr!S6ry@@fNc}8NKW&XFdhiu;;0ncge~$1S^wtvHE)LI*$!> zkp>M>CP^mbLICg?vFQ*L6}U`l;mcc1^x&(Yo1zdh->k-<0SEOyu?t{Ejf*1+k)=0- zv`WUNxM_+`wut2zgvq-%Gz#nifONs8A4J^w{Pn_nqP|8^1|&@T)IXLD4)xZ^hb7Jc z6{O-X+VkRTHXDfCv@BbMZP07y*WHFP3G($ufh~(s2wmLkdQ%uztI(YD*Zj&=@T7Cj zg>Qf9%e)3e3cKxGQi|54t-u%+%Wg02{~?9F7xfG@D%v5Cj{+WH z0C>jBe@=y(JItspUZ+!@_*7V0PN}u=!a)c-OXLyJ+nErQHout9_QsK!8^-ABQ4yur zNj+?mhT-G^3tEIG0`L{L%BuLTajh-SdD}+$=XP6PJoF;;!jSSoq0D|gDV??8Rn|ek z8HmIwaO(V&Ut{PEl}#bCOnt}Z?l>^jEv`i{&{j*wX$@c+K+R7I2D)ZbuCbT}PfA;) z%q=NpS$Ir+tllD4<6YfACsi==U8NI)XxKDVCQ9cRObsLdcyE2rZ@}25&2Za|H$s&3 zv}3^gJ0dn9ft@17ltA2 z)F(d!<`+_P4(@s^rp%zTm_eoIH%cWYb3YV z`lzdA1S6)bGH1OA08GfpQ;5ZS^!<~B#YSaXNp9z(Sm`I9pBJ?WlT6Wy!sHF=`1w*1 zGb|LAq%(%IU^e;qI0?n0$s#AjTG143zOLmQ0t2A=QS3CD!so*S&q0Rc?|_A2WpaCR zwG=3L7a?Q-;2ppHzaj2M@cmnFRj-vbF+d^+sB}R6uZIfAYi($?)cxP-S_&Sf0w1Xtik%q4MCfT_VX~(xy z07ykx-}|S30aFJK!UK2S$!%;}99vP=na~nYjASqcAUV8FH$%f)Yjs->e&cg*)&|}! z-~vRsx`5231wNxM8Vz%i!)C}Z>nqx^ywchi|qf#t=N(i>0Q3pG5sB*@Uuc{iS; z2mn}oVbptbqLJc_k}nX_1+7*o{4FBln9*f#7eL(xi-l}7_@9dkA$u_3S2~Q zc1Li11f6t@cf~WKFSMbs+_zb5DjZ5Ph1{B-QH=LapBzELj>;yPxqAd7v&+x$4ZM`& zlGn?+1GQ4(lHK-`=rv^?%|N`iwC}K>0BoMmv0h7E;L$Ul3`=uP1Tg-6EzK=B4~^qYVaHUmivYm3`3i3; zL0;A;;E)#iif=Yk971lkDemQmWb!#_(UzRF3m_e$N#ZQhTr9kSQBRO^PLGlgb^vH& zuctX#n*AfE!KZ4Ys%*)S#cUY`EwXV0F(6?UGzeAMcMpeKp+p`D`C zjZIsisytu2t#e5%-YEbWB2Igl$=mtIiKPTbda%N@)JXDL88Kd%;)|yNz|$cx)Ks5G zN@b@PJsy0E_VBBH#jJ7`ns2te->Vw2kfH*fUHIVvfRw{;T59r$AA`Iy(WS$_c?om# zo7Nq@m(0lVdV@gFmvR^qO+Fu&j!as9OHpwy9uk0>If?ahc0SL=%FS*;xa>LI*G7-0 zMP#bA8vNOgFTk~*{5UM*JP&2$>OED}xx?+ifGoh66svkje$uIrnFm^0YtKJ?!!>V% zej$*aCmqOl1`7TS#ecJq-e+{I>OC$hJbsnTIG0^HrI%RNrjqWfgJk(ubnG@2+>1R?s0( z1`-kjthjZ>YCSP`A3W_IZXvFD(+gj9-O`(LEl4{_sJ*HIwye&7(fiA)6_bEzz#S5^ zhAYE!&oc!*Eilvml3Fmc$Ustw?!>EZoL15O5lzbQ<5bXH6Xsusp4Ir1rnpIR=Uk&< zJ-~jkmvrrUD%<881-2WFO6DP4@)oHT>+a7PXFnM}@R7fUfBTD%kQ5l2S)g?Q1eF81 z{?J|HIRLi{fNyVcd39>fx32x~1uejC2|1`}I4E+A+_y;N_(cGo+)JcifMT9Fx+!*JmE+^(Zz@(EoGgy(5#lbHK06Da5##F zWUBbCkmP#w1Kv^Ze@Eqh3T0BMa680NOtxwBDtF z`K6_UdvE;0dmZoIE(rUJQh>Oi77*nCAg>K@`~aYS!OJgA68WDb1xCab0VAh937Jjy zcao(EkjoQvvlnu)^*ArfHLZFJb%mmw+K7rG3*Ik3YR8C+Z=%3MK4K3OXkIvT-?Nis z1^|5Zh4mr?3lJr{_);x^;#v39Yqk0Omu?M`eT+OV`lW)I83S?Hn5h4ddHtbFx)D*RtvRup%D17IjII1##YgVY?d;f`7{1jaJ+RNd~ zJ3d1|9BS}|fOi<6L>|t?;2c1A4HvI;4E>2xhPm1K-TQC)(r-DfKerPQ=js8jf%iO7 zK+!7kv>@#_f@3GyD=%ThTah4s`Z8x>0pt{v;obA9Rm_N@&q%dZ#nM{NSO4+H#%!ZVvUIE z(R2w6xEj^rLQzpi48%lA`PFM#X*AiNb~uD1e1E23=|)Uu6LMNhSS&2GrGgv&9R*nc z@Yf|Wa$qG?Xt!2E+kE zYS%p#J#|-E5?q>ds9w+P+=2ptFaDO}^?d-)g?@$LqOUiyH00QefVF45^rPzaUzw%= zA&j1J4zyb-pFEnlA41tl9n@4v60$WSgn>w8h1PhV^1L5y(xN5}|6{U)_rZ3&~!Ra$tswQmO{z zEJ$@9?=`>tHaPdZr@_r%{W`x_^?SJ1ogfnz10xL>0bq3nIwS}ho2`I!Oi#_+bMV&d z|HuJ=ZqDQ9BY?=`_19Y(a(n@xa{eXPs=WHAP366!PEPZ*Cn^9)Jz8|=E~o^2GZ$S@ zKfoiAOugW0pJI(oC7-$IK=?)$4=G1y-(Ubub7+7p9 z08sY&_3Q~f9uk=}0Q|QP{x--+!u@yL#X=vn^G}ZhBNI^F^4(q=Ix8#O1<-9w!v>r< zJbBxp?|tnrpnn)B{}DNiK$kO6G!+i)2NHoDscq|`mR~QRY`Lf%1uofQ z>@xg(3O*)n!GpK`KwmUr*olT&>egKHRsKHB#C+PJKU2Fo2+L*2!;m5&D;lCjPk!V7 zd>AGV9EN=l?1V&ne~GnZ?dxJ0LEK^C+3p(a0ScL}2AnuNajOD=|38=K_nefV=jj9# z%>zgeDEK0PqXPhC{0;RuYsO2UaWpoc3bHnwwwb!>W|+9o=Bnb^IB{uED)xW-o-^WBiDtVh}Jzhm0>(3*)6vs*Fuxl$jnmDBuT?_)4lLb65``w zXu6TL;H7&1MhjqNF%xB^b%;9GSCYtCn;w*qsbnsdN{6BXv(DQSM(4Ev3R4LyPU2Va zVRb03?iY=Y=OZZdSbd!hopOZhL=)zkx;q$+40%575IU7*+O*LOknsB-{RDjfmRn$I z{GfhBmd9t+9~EU{rwG-6mRF$DTcuW^G+hAo`SAF`8xP-p!{0)77 z*|6gc0GFJj9_B&!eAdRcs~u1{z#hvCS47ODgh5T-{%1cc7I6)90ut zn&7k}JfgJ2Ej)i@$LHZ|*L)u4r)Manmx)mW5*+R$J5m8aM*%>$w`zt2DGI=2{NRDF zPu%g%e=I2axfI}@6BU%D07apH>>&aj0{}ejk{79y@(uPX{E)-j&x8ol!W>G0#dG_} z8|ImQrkF=dLA7_WMLr#-_wNmm)|jXWrn&Y-o?^WspIMgSTXcyW0(?)tIRVaPd3QZH z3P%Ruu<&FIrFc+Cw+S&tiK9%5&=mN}6opypYLp(Xtyg~eLwA2zZgThj9GO7^^J4aT zfsIu9#WG7k!YRz6q4DAky-}x#F6<2NlmUQU9kx!%v_sTu%eK%2i1vr#uu$-bwx zA^M^T;mWj2ThPYy^0#07D(v|Ce}uJ_m9(yogdn{bB*r2jMgUj?(0mLxuspDL@AXr6 zefwV=Lw5^+-2y6bkv2f=i3Vg27~r@R0V_{^32Fd*()HfMr#>;GKa5gf$OJ6Y-Z!#Z z`HP+157&as0trjt2>Ww*-AXg9K2w#>7vhYE_lb3wIs4+Jo;)Xz4vs)!3zBsTmimP} zbQd5?Dk`2P%<>3gn`#)54t|c}ky)$sQwz84j{)Zp>{PaCHf7S{6qnyY0X$1Ci;eO;H0+mGo zM-2c-UHl{0Xoes6WLnE@0bq77B&#!C01#&5EFv_ua%ABRTv#A@;YfLi4TwBoJVJDBna{Nu)`v0yj^ z#+Xdcx^xtn1Umer8$(E9BU4TwBzY-NtAHf5+s`Of`GWAj)z5s8mM)qNiT=pv@eWZZt{6W~K1{RjA@0su47oPY*E;O-4Bz3r{8 zK}Y?KSpnzXn)@Dl=<1n!Z~k1a|DT@=h#;#2uu%ZW>jWG(0Qj)_^e#6fZ9e`fRtlW* z->F?7+e_sDpbI`lf*!6auW$9XFS0O2K32+sKAt?U6z^xYx!iExa@*?b0NCQBuXSeC zh>KT_S%Qw)j#DJm>Ck+MXq3-eD;2%D*nqqrBsg+#3YAH0qa>caU%&YPa@CT*HNI*wHEW*%NC4a#|6O_0o|7>n9fXEpiJQG zr=1V){=Gkd9slr8E_AV+7&34}k+^)L=j+D zt7Ylf35EEalgrYaoI-6F}v&gUvnaWZm#f`9|g|q0+azjzB6!qihv3LXdj@tIDtBWLka*Q=Vt94yn`AY z#uyUI=F76f3iEgz@746u;%!2h-;H^5z%q`&x-?-&kKcHqEI?FjF{l(EPzbWy)}A-j z(X$+d67`w&=J;)eAEOZ3G*d1HlA$Zx-FhJb$wq1sE`2vKfM>fJLQ7?XS9HTnXA*b9 z5!3Xw_e#}(jED(p{W~3y%*G?FxqvAoiN?mU13B>UW<1 z@>jr5z3z?h)oVV_O+Cp}VE$S!1;P8EwFavzt{z|-0qnl(w!fO+bKkAG0-$T;9q3mG zcK^#VTQy}l)m6|S5gL$)9d@N3B`bHl=a^;AOACtiHtx5q*!K{ezvXOCKe2w_Gc`uw*yUm4qdf{bygJg{>T^Lea#4{Ub)?4c7 z1qi*2!|2}SM^DRA4C95k1qym4dem2_Oox$Hyc2U9TN~EYDOj?bo+lVU_78jubBraON z=B-!2Q=a}z_};g^MaD011UTU)Kc&YpzCT_*ySltg!XO;2rNHvQ&ENXa^2FW;3R-?$ zDBcxNv?VA3|Hhzv3IMinbd&&aIue*n{?8zXmQe*weO{_g6EAWTX-#IAsV@Md_HC!CVf(8 zriS7h6VFF#8=A3z*{IL6(SEuI^}BB105!O(&4x#7CsY|YIaEHL&C^bZ2%6@elT0Vsmv zQQ%_-fa>`_`5JYyKjYqf^=*$w$<*}GmnMh^WQ?INleY@6q0OaTPs{+Y*{2XjiwiN0}+Un_KKjE^RA|X?`u7|HH4xY&h(`dGsRa@;4}LG`i&`c_8LGTK(HKG zh1ZW4L_+y!#aEPbH3fVee^;O1$G*(0OY3&B*T&haXx?Z3edQ_21}KRuVu8Xx$KczI zm7W)s+f@WkU-#W#zwS5M3$qg? zDL}MN4WOw1A3^aX;IRY1<6ig9Pc^n~`}ss&q}I|BM6I^+{^}-aD^Jqm(OQ%OOO_|C z_X_k4DePyT3{w^y$Ov?S%0>7xDzD)Pl*@%Tyu~rMdTwsaG=d1V8m%Z!FRTQ3K+y+k zI#0ejK{jtM-qM><7S;u{qTk^e ziAsqY5RN$WT5x$o3E2UlHWcdt7PSF=08mB(IyNHEsjvRkJrE^N z3aTMghSW(`h>Uyqs*O5`dJQU66%L?U#giQJq6D0ez{+>82ayWfTMKinlfJwJt(i%! zma@`!lk((Um<5TzzbV!({tTFM$_AE=9?Z%upIC>9E{f8Nbfp(~_3wEUI3U7{Fe}jA zX+obCfhpt(u=;e~2tW&1_yK?md>loziaocpe6&9j;d74wfd+>lK|?aR;$HubMX-dM z#F<|(th_P>AEWYvM(JZFW&oh1Fj=lHoZUujbQKaUo4($T242L%j^*#J{~GN0=*OUg z?LAsVAZRO)5d}qOh}WR4oM2aP1+rIO;>xfDZoB%QuYl|zP!IYALVb%ueN%uEidTdm zI}vF6&tA16J8=^W8K!4X%x9s+HmVh<4yio1(NN%^fT51ypuTRX3qsyeU7Sh)VZfEr zN?0S|#ELp0%X3rEU7T0Ow@e_hGBv3HV-Z@53x$;1d}>i_T)7}!}D51aQsf`GXI#NXs0wtMZrEl4XD{ba3M?p|x>aKt8z}4n&dkT}OxM+=qOlv=p8o;)fy+z{iNvLkJuo4j20oQ_4 zP=h&gAm|)a@C29)BHL!(ing`yZegw+azLtxSZ^_UoCXj01Z~+=Bx9Y95;L9GEd4B(@ft4G-!}$nW-5G=TE(qk#36d}QB` z%RXfATW^n_TTj5wgl`qO8T>L1!S^2BSq5{ywx0et`2D~87<}p4HhzqGo#W*y{E2$woF}^btidS5dwPb z0RXN~4AbK=pmgA@bAJTh`-guDpZn*JBlCexi57$CF<^`dlqc*)ElO{(6TsVmz%EYh z_M+tbpZ~-!YXE5HjK5m|2zl;*eg**6nFBa>0H{Cxl9tlGbT42Rr~X(8E)J%TtG8adrw;=H_7L;9gk6s9|mv<__%jhL3?0J#gd@dKO%| z`8#_lnr3s@V*Q->k+guBlqe2+Zpf4;kXz?vb|-?c>a~4gxo4}diGHM(YBRt@*Gel7 z`zW`j9^nH3SHZ_8(UxcKVG3Y|d-9PFwQ2RD62sanW*+kUG(}D~lIV}vMCpPRs!wRS zauW?b?K#hdx4!c?;44>u7Gk4Uf#*k|pJFM$JhkLl&|R0NgN(pNa(&@kF8VhP4`zhp;|S zRbgbcUZ?LPwp2(JNEe!jhRG2EW?EHzup0lIA_s|_fnliQ-zz{F9ve|#*Qf~8Xbe-t z6=GPAh7e+bs-hwf<(1TZvp6$BU@$*14s(--Rn#yG3)7P@vv03=byccfyV2Alakd*v zy_1ml%a@M=7aNpm@o^NgRxVra+|;)EEmAo!+UjKH^E1mY3eqDD4ym{0_p@F>(yb+w z33yoMo@Zfe5pypiLGBK0m9i-zGw@?{1Bs8)>-I4!^94#H8gk)_FM(IS@e26nb=Oe} zEUntFw5&k#@~t&eZ9)JLG9>^JC!*c$-F@9BuYl|*a0JDopc|P1ND5{E$^hWVy8yMP zz4#7wf}fRAH;p{C&;t-W2*JA%^@#}BLvx`->Rbsuym>8weXOdwp+aTMRb{+r#P!ip zl@cgJRySD%tE?53cHo$60PO7rxetyU@M5aR50sIc>95AHiaM|`*-+8K=rG-A4Fx{+ zriw^t0}j8$P`4{g`nEiek-{WQ?cWDWv(vCNGYzwc55e5{0b2Cnt2?-Se^cOFuP|w) z&XfV6p_EMmZiFYW-Z(M;&ZzFWucSjw4oKj8sA_hnZKH|68wruTS=37ldromRRVVW2 z+3U6U(i+M7%stZv#h1z{hs>r(>#POKcQOng0uM9t{IZ{W4gA=PUj{dS{hQ?6nEV5F z*oT~Bf+Q;y0W2=_W?*7*OIrt6>nH%Y_LIMqtNQ1?e|{{uY$=E=$oq>@fTIV1>eF8Q zn_&?Co(lkJ`y^Wz<0yo%*qJ^q5{NZ638W~lo zKtqMW%Ihnm9vT^8L&hZxh&~!1=@@WbpNT4D3X85yWAWJ#v@$@s+63mpGdF;HmHQzU@%==WB zG7&%t0629C-#$qfBzZUFf@c#k5BSubdWx&gRJ4SK>E){g%&&gy6>#oTp8i*gH4W2%CMl^uE@M5)A`Q{XXVmfo>z|ZiEH^-kL(%>LjWXq&pNu6<3X@ zhpE#VW`15Sz62OC3=I(&45^5rHl#ef`gao-gpvowwxcAmW~>W@!iY?0;s)xtBm1zT z!$$SrP#tR+RrMH6sAJth{kt(#S4M&1Y>=sT>sQV~qAP2#G&K&B2lvB*0tN(#Lk~Yh z5ya}!Qfb|RfWf30cHI{EqlZjbo<@jG_xpG2JwO~qVo{swS@`avm;qpU5jrFXmRJq|I=a=hmI8o(y)qX8v^^bwqUwK? zGkCWSP!#^VMZjax19;JAD`EI*a8!WPRDe?elNNBuA23TwNLwK#tJ6EwDLD{T``Sn- z#8y*H4WSCcq!s!Csf?N*Q-|N6$ry~}yy>^nR8fPvY3j|o^7Nz1h*k8UJbz7npZ-)C zeSi^6RXtuTp<2al$5I=jNWood@e^YEsT*fV0YampJ}dB1;dZl$HH;bzVSPfqhByI^ z8mQE&{syI?l%Y-Sc^GCU4#R>1hFSIbuu3r&6*yom!bfV!avsVEMftEi-CpeK4rKTY zp5>!oZ4!w8QQgUtv`)mLb1#~edquBZRkb`?Af_Xh5i+t$R=d`QWM~)PP5jA?ur5ci~zLLFj2tL z^6Jw4U;6j|s*OG`30Bnik4gwYNp2QEIw`<$2Y@rwMSDo40z>(#vPlEnTu74yFrs$G zA-T$*Kwz3C_WSg^ffi4vztxd|sOj%>uU-(?a6N%ihcL|46rjp)U(|JCFHFS3jJw9@ zW)&$QASgo~9%65=QVTR}6V{pq4}se-A+OIx%~%IH72tIcDmsGU1`hNL!7%3Y^$Lus z$FA2<$f8QWUvZX0;^&&+t2F-L128i^t-xUhrc?wmeP|pOsYrR)n-g2f>d*yEHA*S+=6E!apX zj&-YaJpd3C;W4Xl9XT*VKBDPVF5Z6NkN*_L#}UBCxdWxUfS6v=ig4VZE)@WfAn3dT z+O~Ei!dl-V0l>fg3iMC^^`L)0Kz=D`(L#`@!0Q(Qz|p4w4hUSPF3G=FDwTjEEKdgj zK=*soXJ(_-Ig>ERuP?HW3V45#`C9O_q2w9s0L@MP9V@VEN-CJW?4SoR&~5|!{N#c~ z4j?G*WTFum87Hk@kDk4`X_!)pn)3L~W)p^0dQqu_7QsV&4fuKz=eeDEZ(@e(1czot z)DM~p80yHBtkz*!Eg{`re^EyQ$VNKQjg6`}V-> z)Fgq!^uYt(Ym`YXHZX`~3Sguos8yFZJYMb_Cr&#O+>-S1B2s;R(YM7YJ5tnuFCcNJ5anQFwTYkiSs$H|L^*jq7J~Z0|0@* zc`w5K03Q#6O28K?qpFm4L@X;zI;)XQ?V!RsddB;kXu%Zg@MmZlN!6h(U``)Gq77dN z=kd_es>UE0b%e1jCuK1gE&aX$g(`mv(GWuFF7TRXex7>0O8s$+7KUmSGUg!_MQqx# z*%mH^6Zudv2vZT@+>p{D`W;Ep4+AGxhMP_7mn-j89ad2TMiJ_cMC-y$<2Zz4YBHU2d!mcsbI(ufld#6-Yh|>h$ z__j-cD%(QrN_g{LMw#*j9A+Vg_ACnH(!c#mMK%&DP+!UbfHQya=b!#GeD#_y(yYG( zQwZmKN!pzN7%{BD+R8j6Gzcd$Hn^~`G`;isPrt38&6ke`iZ}p8y#Jy#U_}MM;{yO1 z1TIvM@|Wt=KPSjclsQi!bT}^^1J(+vX7pFMFNJ_2WZ{Is{Dc7j0fS9QrePs*5fb+B zjweR?F+C+#Wvk{41R219u%gdVUDqALR2MGfI)+V2Ku07d=0LIsvAYtA9I&=9gdSdj z#0Yu%Dm0qIFg!A%0}}&&HtFe;(Tb^1iTe`;hY(2*gH>p#$D$5}@>*jf4G7e~N6-V0 z)YI%nKc=mVsK=g}oP@c_379&Jg~SVo%6I}^3U3nG zmLn?*&wImhvoEo{y~jgN_`1tvzTA!i)(YIksVP?=(84MK_~hB#MJ#v@TmbmTFMkF8 z_3!@)M6BuJ==BrO&MaVY@Q5knYs*Ut0NUBdSJ!B6Zt>8rul&c`a~{8}22iH@6BqRV z%K!l2ShfQf0KtpYr_0pGCFY5gur$kG_w#{gaJndqNdSVI`3Q)jjZ>lzpXi;noeO4my-~S0GSV23%K0Jv@X(LryP{k>I^#S@y3R+rcr^gUW3um8ee@H*fK4sM6a(Furx8PB8N$p$L^<;Vt#sx z>JBpp4k$zPuhTZEgc;ple~cS!8%?^Rp$_ZN^!Lj)8M#~m1^{{V14DM!p|072dJxFW zuVjcte18}Kz@fIk`SO?H-~Z|#9A+OkyOMxYLP?6i33O2o3?;<092nnMe1FW%&L7zI z)z7@s@%UX2@h1-eNv;b}#QQ(708ju3&rzSwRv+i+&(EQ+g&0dEpfoZgzb_1J>Te?l z1I`Nhh26c%7e&(Ig+PBl(Eo)LF%TmoWc6K22aID6gY+~6plbpqXL0HS8f4hdhw!@B zUk2x$e-11!trBmbv(kpP@=}wBr`5$>f#u~jn3$S^R;vxObMxx81!+43dF^2(t&W-& ziIE>uHyqXi8Y=v+sn?Fh!qL%DXbd;0t6GT(zvNX^bq2IvMG4W9Y8VpKlb{4cW^EhFkzBjyi;m8Z5P1t4xh<-3ov5 z@lV2M{_zu*)56Pu0{R?b)Q~XX_0;P`07$GBKzff)&&=(4=xaOP1^r?mMF3Eg`xj~d zNhsb1+%F38NCH5?lhKQ)oO{tWbvGy=fM=TEht$G(*A)JT`aBvAKqXCA)PIjZ^9k@vSNkNB9UjIqb8k5(v(7}```t| zOh)r~k9*RS-~)g3=Wy+(KSQqt$!6H@PAolMzh)Jw^b}yMtSnhMFag3w3{%t75A6Q> z)xTbl_ve{_iD&pn<_3Q9hA*LC4(#~W0FDw2LU*a%zq`U)Yr`P|2V5m3b$FX#3XtfkerQ5!lRju(Kt-7JONZtG&u!b6q*DU=P!ASY zVDr{7_=PuJ4)^SQ;K*hskUUZgVbjQF`WgY^n>XGJ4?MJwt{tWTp}KLFS8*(u(-GV( z12mWu=-CB5W}UbTCm6TUc3xvr7^5hj7<%Cj*1jE0zm+xXG*wE(r$NQdjDRSIeZ8f zRRl4sA_inhE|qW{Y-`miOo|P5E%JrQMDzRe>OFo^QI$0Vx}B2wgQiUt5CG15=Ck0+ zcfTL5zxF!a0*rYk2Dk%YYarNOv?)Lj@_Q7fre^Nn{f(>tho|Zv<>mu?+<&NOJ}*yPtF3lc@!W#XKBZI@)7)W)61V^AP;>D_;sPc)^9x z#s0erXXodZp`{FGM*Vzteiquw!ycNLg;f=5FD@+DmZ@}BPn-G#8?`C0_Q));u7H4` z>=%YrL_$<&<;5_qK&=MspF}jGA;D1g6Ac8hj-T`_3$N1>l-%;VYxOloA7d&4YMwfz zKw^Y+9Y#l+^tqvcBQ_PBgtIZ@#Uu61(+@ugb2C#aYM6rQ0}3d{4-#8)X=<|krg2gW z%X<*(buDs*Nwby?*PsEbLzPW3rgIalB4q&O!WX{;Uik~Z2sd8;RrdJ8NnK6nCyH&# zfE%1S0?5A3iHXVE_k8o3--PTE(6SW3xBAN${+|>8APU+KWdM->ov6Il@WQinjX?nd zr4^>;a1LHHT|ftwrXLJfBiAnrn2L`4MEN|l(3BM3Aq zG~YBjLKNiXrIzv{Z3PfBFu%B{zFvce9^MagDo-arEPFKN2qJPyKGGd3(C5VRBLLxzWN(k@0Eym^@8M<_Keq0A^%7!Ko-$I0`sQI6 zQI9*UKxfPF2y-8Xt6U`qF4E%GoJzovO%w~5Id~A}rYC74b7KF)FgG#Iqub*L%5Sht zdfjyu_1y5STU1K%Aazcj z^5nCqz_+-#q<~_U#3)l9a|}8!VCxO^Wx&uZSqXh&=Y-u(|Mxm}=KNb=> zr)5$mzJ2UKgi`9x7pEFPSdcJysGrA>SP(Jmu(ppWklfaUVRf#zHn%`?v;j?&jT@>m zCyNI00u`YonkmZB$ikrsn4eW2)6+1ye~(Hjrf8gdX5XH5z#-ex6gdHy(qSwO1O`Zq zp24f${1!Ox>Cc4k-+reac4gKmR+M7hR>a6G=_mkDfYEK^P5@?Gx-GB62gkp$_uJR~ zE@U+U^9w)|D4zX~a|R#hJpOtBa6(f6Q4k6ELjL^s;^W_;c;R*p2)YnyLE?gdL{4k8 z@iZJ-+FwPKAZaSc`5b?^kUODS&7aL$ZRySL(bpH*ckS368yL zCOj265e(vlyBE6YXk8NZGN^b58b~E!68_FMl}0qTsZ^!92{vyVQ$SaRW|eCXGSX|e zD`;ebz$cFIwMm$pnuFze1qO$wVCK+4SecvQ6yu@$y{p5D*^)tKAS=%cFnWM*eEU0L z+qTo;!JWHU3PVF9v~3wqz%c5EKn$LIM0a~F3`1ybCd@-oxuUqiW;@{0xcD7LO`xm zC%V$F+jogf*JY`cMBv6+L!>^}wF} zFgv>l?|#o!aLf1ZfVH(&-$@)ELW*q#YLy`vQ63&eR8S9LNEz{@@}_Gz+N`36ab-9= z@4inN44bPkX+yyGuCOe|L=Uw^_iZ8 zCg#;yQismEm5HE1X@)LFntnMx-`344A{lGKsCw*?O`Bj7rZ3GpG{=T?ZC%o3 zMu*5dL0w6FF9LTm^q{@G3>}rSsSv=Lztp$Rnv4=+DN>af$6^%-019XH)c&ewnmVLUZdWRD480XezKk z0aYp#?p8OTGQeN?)vMrsOa+eO7$Pb6P=QVbc0aHa?*9Ir7PL^)PCDT`8UAdOUuA9!GPP=F%1}Xl=okR?n;~M zG`Txl0l?M!zw^aEf#UUFy@Kk$^e_NriT6J#QUITEiw*q#qY41e`PnyKs`C3CNs=_! z!y7>-sc()%<=Z6i2ptUwk^0tQ3^Q znt7l(2mD2BZAX}YOT)WTX^H}a0CfwHwKqJhQj9UEsLw&b14#7H0Y(Je8U?*>i|e+$ zc*D9reR`;PXBnIvsZ@q*uyyMe*sh|6k$MA$M-*6$HDL4b5Yf@Qnn6x1KAFmO;27`R z%mmCGIs^;zbI_V!fT;uf;i*qP11|f;x4?J4asw-XRC)ekyezLNuhqSl{J_iv-@zmuX3xRDybhPnWcUM18b-l02DIH#*lDFk-0l`e_|WAkYZ2 zeaD32xMe~Lc70|h0f|x=ZJ<}{FrYxfp*gB5*GD!%1G^OJ#vj?T1?t!yY^bkQ?j8jF z)$s@Kx&y{{KTKk+RLM?+rLHoUAPr(sSyOAs_%fOM>Z&zzTk-3$oZ<(1d4gi5mtn-w^mws{Ojaj0uk6}FCTh8jjKVMT+SZiDLg@a!j?3fme(@XvqqQFUE= z^v+`{Sf&%LROg_zb}i`OS}@%FWjGl6z2bD> z0LP{WaGU{PJy3X5B7h%%&08*2H|GvzS`FgdgDzU>sx*MPq4|4>{+^W(r+ik2oe>jM z5(;g(4~-!%u8!{ZB=zPaTqH>!0eQusI>b|L)dm5DAf7{LM|JhwDbt(P-^8dnhbe^u z3PE6@X9Wx$P$Z5dRY3ZRLt8ehP~qA%(NT z^w@14pXeHhB;XMGKC~r3tA-Oh3spr5rb1dKp6yzSSpS?KgT!QUW}q<&0=pBq)dy1w z{5Rds37%?>T(B5P6PyVdd=iVauAry&5~n+2CeJ~4J47vjQ%>6oTSm7)Lp{%?u_}y> zZGx9S^C>V?3E|^^@z*Rvrz0Aw`vgKiE}AUv1ZY8fWtrCFnJ~q1A+Z0!T~{Bx?HeD0 zV%`5D5CG_x`*uRaLgwE|1puO?IOuKDo@nF$iOa6IRNWjqlqYXk&#rG&BmHGK_iT)b zZdYkTNZ3Qt|KeERR58und&bCs!dIFgQ#WzKQ-QHE?1*ltP}yKeGYWx< z7{WS(0s#g7I~<}~f}~|45l0J&<_BmmOx`)+P?`<0$IcmBZ)7zAt1h7wxJoNfNjWhz zWsuqk`F)VzRj)UsR$uD>DIyRYdJFx#w)U?tuABb=ij{whKA?aB2;dj}SnuB_eG%}4MgSMT?#fHmDcPYy_lBv2 zyE#8N0KkBdXiqEC2qDo%5bHiT8N0Njud$hO)ACgqvL`*spJN9kjCMV`9Th21-W+iq zLE0B!*m^PP(k05+rKk}g;NTQ~PikObMr4h)IFY7;<~9T}w(=xGDQhgh_e#hh{i4USRJuq+ zIz?{gB7ma+>TpmOK&1dnOLj>u{@&8;BrHsh)9aC8EX(6cDB&H%1uzojXGso)zed|q3{H#mKdJa|I+ zKi-@%eUE_vi$#*Cs9Y(>NkaUa*mzm({kgK05FnVsU}E_Oaq9DAe_e<`0mD*U#ELmS zGW*oml2*CZdB}=t4C>cF-fwU8kiH#r_6k;99ry?wcf+*(s5j3&BFg!+| zu^?F+8HE=-VU!}fkhT+PwJT`^Zv|g3Er*XBfZpl?blWJ0-hzdx391PgiFcLaePrUE zTRvKl|Mws(^qKeiaY5f-90dS8YSVzSfEVCP4Ic3n;Nr`b@e399OVLPc-H`Px()BW_ z$4{KFHqj{ou7--WmrTqST%GfihmTW*-lW%KL#9bKjtV$UkUDMPq9KEbsWHS{e@vte zxxrF#UBeNXG|_dY+Bq^P1ROD7v>>rXiCTart)P+Y3VqOWjG&^$TpVryb|DhbMz7}t zrKb0x(Z|TFi!?}3-JHSEvgXoCy>NzyIIA$aa!H|&Gc_3#Jy5lu7g9p?iRVD=aZiNC z1IQ==UxDnz{;rAa609eoP zPiO@2!Z-X1Rr}SA)UYolaG%u?*|2w=@w_@Xc7!VuomZw(~8s3Khfbmhy8l- z2Lgl!jmS)`SxIb;03dN5Pp2HhkZ%MprAVWIEG^t!P1l!0oA(!_b5JsL2Kuou>9@+%tivz0RoUYbCGb?lh1`S zpKum|OuM~GH5PnC$hU75C~fB&U>fszwHa2 z_Fn|WtG*H_p7~#|>VMMk0FJaE_=o|(#cz7sr9mQ9*bfaWS11LP>;csd%c1(}b|BeZ z%u#^UEwMxsLW~kE7W~XeD#SY1*9Abz`Duw|M8q2YS)~8owAp&LC}_N0T7%FLfCeS5 zcqcB6&!#W=SP{~Nwg673tyensHJUm19inJKYH$FG9_lF|&|(wb*u>K6p(X^e)}C9e zO94PyHl#hb#>y=!f%VeD)(_IZC&ggBU3lA-?}o=+d@(%ld86lXuB*ny6yQ+-fET^-s!LV4wnN!zBU6r~oUUMQ z$-N&T1pv1X9&2(C-hhco5n_|C>!P0(i(rq4eHU}8!c>UVOJ_loZ%p`)=XU$s-w#iI=}X|%KT?7JroM|>!~d*4cHAAo z?(43D>5u){5!^8n#>Te5&%EYM>sPJSwR`A$U#9Wl)c839NP!@Rg{i}@n%%qee(-Pn zEff5N4FZ5XQc}*NK?FLX0PsTP`IY6VuwOJx!6w~9=)4SJ?Ohl9a)#sdtfelFu~9pb zK%z%Ob=b$WMVo=wr+9Wz^z#9iBLSSa0)Eoi}0x@I;j}oWdW@*LN=$&yC ziwCB=p;eG%KLF&7-0pWu_gp$F+zLPY?ET88Vd?tMI)5YA1pxfL z*T3;9S}0O>EKKZynF9~dUH~%s$QXW4rvrR1?7HbI=flQSf0L33Kt9$0Apg9=$>_u* zT?D-NauxPt!B42LU*EBOfAXqvVI&7d#^LKmm`s^z(kZG*hXJU`D{hWXqp?ow&w6yU zS-VjeBY`dnN+zb~ADK{J|9)(^19943(`&l9^QM0<6$7-KeYQhsrB!WfPrLUdZ&}iL z?|Jzar)H4!C6zjV&tFE7MT+eI<3LSK145Oe1p)@_L}1OqTogz*`*KDQWS%q8ybaSq zs6F8+FnrFr@YKs+4bOhw6V&5{aQn9(f(QQnI#}C%KXec5-eCBj+R@8@>a}p{X^$`Q z{t=AdcN2+$MB4aC=+po~+@tH;gK+Pz8?Jddl#71kC;pOL-~X75|6~9FcUhqCbse_| z;3BN{hhm3v8VxhRAt3#1BY+@VDU-JRm$n5>9-7jEH3&drI|8=SuS0bPgGf)NIY5D4 zT?0cL^Y2jKI@YNGFk6t@fU#A~Wf0(c0)r0|R!m*M76X&CBOr6QE1enjOb8CHLbGPl zC8?l=6-=^`l4%2q%%j<~%9_6@yv!nhD{75EdM*S8fxuAJU5k)rDX4qltPV5zjENq? z(J=_NoC2fId>)+gUw%wIMg^vCx&c=2xecO)8Hkq_Ht7A+d*L}h_Ck2t`OozJ&iug# zU~O^68h%VF$J+4mv$|%>YprV@`qp*t2fyNPzV(+tx!m_-4gm7q0JkQYo*h6GNFHBqXF%4wP1)baH%5!4*A)@O-dj&+b`+q zq9J+sm{@4BjEEBubC{r00@E4LvjCba049x)iB1EgqfY=_I28GAfXEoTQ-*V<9ijHx4Uv6FSt7vMB%#2gOl$@4a`tVRp}bJ7N8~ ze;?&HIRayUOaOp;IUbQ3zzbe?#ic@o%J^jiDyheyt-Z!`Sx;iTh{&*&5^$^I{PRTD z0TN9^BQ$pMU&=CO_k7C^pOpAzMii0NNi1j@q z!PXZ*M;kOX7pIY;o!FCUu@4LzuW+6u8yU!a-!{`VFczAm3tIYc9!iW~WO8l0>(Q+N zfN;_QaDInDqt<9B?>j%YGIMyBc@tuIa}%o7s;Ja!qBb&2!U|!nE^uY>5t#y?iLtHQ z;b&fTdEZZw@Uu31kV1X(^jbUw4S%)OTAQ7j{8#1m{}PH7e|(~!MWKJP(H{R}0RYPG zkmFJVc>d2{aVaR{S2tyYi_oatqKO;I0;+2$n3U42yztw z>74<~{-$Bm3CG~Uw%kmMR@l|k!i+TQ?+uNP!s6t?1FiYl@dAU%GwXyH8lg=oqB`8f z4_YZy9a3M{H}Sst{sU(uE`Re?nLQM7YY{q&(>CNskFS7R&d$&6-~IiY{$OVJ-SUT{;t8>-Q&0c3nt)Z;8H%t74gXvu43B$a@?cNo^` zmPQ4fQ^vOGnRM=X2kMf}FD*fLZH<6{wD{FK!*ydbGt&eb$dFr|Uxu|#O999VtgI|U zyBEXS%8L5?9v29aheonFI&w%D9OA@G`x&pEXz75&&b9N|PONT$aEO93bGps&kI1$R z9euz401li;qu;-0VIj)~PYqt$G%REM(xe4Jwq0xEGv4}ytKH|u_wMYjF3&q}#u!wP z`!_hASLOGrXrwtBvOE%yz*U_s)xO1Xrx)K z1`S%h)m>|MyHU4>Yo(H2Oop^DGi!Ij%}!6+(0_h*+Pg2l*fRvArb`O3x}HEiX~Rbs zC{eYQX3Omag#NtklvDNMFA1X~qomhY9je0!&buo|Gpd|Z)QRBm)M1jDo?BRerTKYi zDS%MXB`hs3aM(|Zze1CSSihTU1|rcNz9dt}NZS}%$v@FE{vt>z&kjjPxP{PMHy~Tl zxw3!lAvldO~L3L|vYElb_6U<+@#Oj=$T6bg75?yS|V7wx75F0Nh9* zKj;4g0|5DCP#o_z;I?yr^l#Lsx1Fdrg5;1O5H?&5^olWI*O&`h1xAJ*=(Xj7*MS9k zZ8&dA4z%|aw5U_4$EA7mP%l3f#xw#FyF^_(Ol=zVkn{kX!wr?%RMh7R)T?!vQ=l+A zH374zhP$u`?WF}fFhr}!l0+9XMTS?Oh?oU0lawlyZg>~DGGXG}sscnG*VEwwNa--p zW%|28{#M|32*%qRtv?q_fa%3}K8H7Lf~D!Hh2`n-d!cwcP7nGewDU%or{TIrZNArb z47lTb^a`Q^^R>J5v%3!Qr>O705sm-HBmh8;2OtXS0?APr|Csu8P<@Q;eFu0~Mb>vh zPl1r$8wsTM-h1!8_eK)ZNPv()5_&Jvd#@@sM0#}<6<1JK0bK>w0wRbCEFj4F&hOq# z2*us?-M4;^_j%5L=FXjR+RU9hbI$zN?C?t2m2q9i;L@mNgWrGA``z*1C58=Jc3tPn z@iBip{r!&Pj!rL)-1W=Cn?)NB>P!x|4K;|VaA^PFRhO;mZQuC(8j-Q^YD3t>xjRNG zRve2o2y^xszv2y5o=|MbC|6Qie8BA35Z4b~FOEHC?d;Nd@r>oZkIjusyS^ydp|We| zPg6dgulms?Td)4FgiN_|S#{8z=HjFCcHcjDJ8$J$|9zfbyVX+fz4+jbHF~r6UX9$p z;M}YM2NF-cwD{)VjZYrjt1?XC&bZPmXCKblu;TXRvit9rdE8yBtuT7t*7v`kv!IVc z<2OIgNIGY@;lcWYeKx+NxbWOmo6MAvPUp&|RTmi?t=f6=?)|oc*8UYQs%zO!&Y0-l zurB+Cf%};+ZI}AKJ3mA9&Gg!bV6*%o0QdYR9?dF`6f zwF`UIMr?2T{DT+2^@{HJbIkKs?8a;<4S02@)y&r;7d~&Ty{AvJ{`vszk2aR+x=)|_ zxlMHE90gr3m%$5ytLpkId8@T7)7^e7$YXiyiOzAiK25)T^MwQL3%|H@_S84D*2wIZ zf9K*0zkL7wy}oz#J5P?fYo)0$bIeDRz8*Bs^jA9#hYx&CoShUg`M&3m?H`{Tl4-if zoz&D7-mtUtnRBn-q+RW+-*pLj;hnTk&29disb_g+@$O;67ko2q)#76gr_NmcVDX^- zw ztbc!9K>NiXFI9W{cPJd#<+1Av-K!H7Poyi|J^XIV@EMKi4J!>cY<>IK`8P*;oNzBo zZrzmauy^SY!+t|ndq+3u-ws^0d3EuaYLjK#-ae|kSfR+Y-O*{=b6=|l+TLCF{hm3q z+fp3=bi@0(uKUdw{&xDopNd{fyh44I6at%udVi)Btaxnev9O~1dtUw9WuMz6%ih@^ zckl0~16$ADvbZ;3{oQN2`DR;pxV*Kmbkn8lSC0hRm5=KPe8Xnxq_vxm1nK;(rp5e? zO-s{^C)M=Z_(ft_+lQ}zua{B%?(Sw|#jQtLkFN8b_K9-ezJosBy)C-mq?y~BzuO#J zY`HH<=f@LsKjh8WuDVQ9yBALVc=3a^uXK`P_L}w0ZPO#Q-r7GceATcOV>h4b)404$ zXTYG9jYZ%3D(ny4IKuQ&ZT;MNC*FIIf5`dBozLg%g?{+Ax#!Yu^G5MXr;qf*##&5z zDNVCcanss3?f1_%IX*~I9!o0SP#xK)4KDNI`mCXzO zd2DX_-cZLuwwKPocPsH^e}iF5lEZ$n+tOF{^?NJ+HnnT(k#}-3a}F5n`yyxOE9;Cu zbKI^MTpTv9kNcs86??*_IcjTfojXMBc=YaBsc$r1`1OvR^EowkeHpyVEbpR}s;|9U$!iw$fV2Wq8NebE{9!O??>hl9UW9uxCY&4r&| zfB2b?Q_<7f(L8sXoyp<*T3^MYGPWoz{vQuC@MP=X6qizsd=-;I*rFFTK9bc>2<+ zoiDG~RQ_OI^>;h|(*MNJ`vVWmocWzXq?VTAD>H{j4olr@n=my|>pSO5{kdD5tkAc3 z(?jotv(_K&qc87Yyfov^vAKQvR%&c>o2<0u(!rKDJEPz7j~{&e(~xpcg@qyCCSA*) z^q00ZS`QmOQ$2Na_r3{b6UK~f)4iqk!Piz-e_lGSZ0@kjzb2gB@Kx)Cy*th}&pmp5 z=L6kczs&Y8q333|KTKBWGFox}?FH*wuWNg#575n={Nuf=w+eQoPP#mB>3jOFT3hP# zl+KNw84`D?V~5AJc&pHlY8;zQ2Yfc@{N^%;$$67@%$#%7&(l{mZ&jG(tcg4;vvoe# zzxm^|vBURW|HUUZ=%r)P+bpiU*HLj`K=L^=4FiQp&xT1`&+CtL`16Geg{y-4b$s}~ zzmoO4le%u{)okDJ*@br%g9pAgp=)f&sTO8#~usTxWCWj(;Z#j zp8l#SRsDZB^u1$i<5|ZqXMdl5Uon4LMaqN)bBy%%eK+Y6tv;Fj-H=ahKW*&)%ljMi zHjk}UpS^YW=E<2G-XH&qb(Yp#ZIhXW$E`zC$FBKaSxdd^XNv=C*PLwl#=pZWtM8R>j~%o6si6FU)n9I^ zDHJ!J`RVzhi5Gl^z4*ZBov#;}4RzYwF>Kf2kMinA>2K?kt21@`@SpPf>1|j#E9Zjg zcW1WTTwvI>bjFu|HJWtklCuBn--kS}|9*VJcQegm-kdPe?!Caseb;n#U;Wm+_}Y?P z&Otu2Zr-t*qj|r<-ucBp-864r+Pe4Z4advDZx%MI9{NUag5B}~UyrBp9h2;B?!K#8 zcek&Cp3%gUwHIy&MU@ZTaYdoSGdg{$+1L8~-#xFE>M0+*=vvWdYTKMww@mo!NX;|T z%`Zk+pWF1O0HsfI`@b>DVB?<8_kPhd@Y;pltDnD9-&(Z9XiL%JOu^zX;#Opa|`Ir_@WNqw5y`nxH7ao~l_MvJBwzdN$(gys8f^@nF=^I^Zc z_bOce#^p6Vef{Z`n-$gm%4cuhJrnlI>&}4R(Q zCimH3|IYrK{ni{h`-9HZUv}lYFSJtFf9s-kR`&as??=79ze<5sdW*MX=ZzbMn|`=> zYDrk<;n*vCH$|FGdw8zq#c2L-KX0Y8Ki;Zwes1B5`e~a|%xBzI*VwhhJ-u$ntqsa5 zbK-vNid7q8YI4@%+pFG|9_2-ivyY{W>_~>Ttd#VqnjypVnIWhlA>&N#yz2>I3ZP;}GtX%``e(%(R zS;?m#rg@}H3jUK)pBwhheYQ;w&x$s1n0@Uv&CE!RGoywqe($5ce&bF|I?TtLys_y< z@{Gu9{0ByLWzNm5lRr~dnQ^BhWvi+2k2k;DyvF5#HYJAaYfzo|=X-lsD}R0Y{>`v( z!*_2(3?`qSbUJkBPVLqChuwFK$a?;B+CC+CdW_db^ASIPJ+}6>FLmZRoLu2IaLc@; z=OaU%qOPYDY&<_Qbj*$cAE%`?^4M6?Huiv%@t{6N<6e66qrVyjp8o8_#(<*Hs@5NT zLlJX4@?#rLD&7C^VpenTnfJbV@Iy;c;MvnoH=^gC*(Wu>`lR6nI{5k0iX$00cbC3r z|3TlVk^QD6^qslWGuX>GQTKV%@ara9`&zGbXu6=(SU%J$V9=Yk?gn8)$F#q4|9FA3 zPr%N-_KNP)XKb8yV8FhRonQFA?jG>)dj6%PZ)bOE{1OqAZ{f8+z<^>MFL)IOy*K{h zrv4@oCPhp1?rctMF;qBq(feWbiTfQl?%8^@u68|l>XmN?#+*Gr;Ke%wH=n)n)|Tc$ zZHBMqOgM4ySB)zX*OCqAm1vCq;%JrHTvK1w?d#iYjsALbXh2p~-K8%-Ilr=fK+?YQ#^w7rTEnhxg zzvuGD^sU5NC)7d90f7;onU(3*MAZKS=6)VfUfNLBD*`c{6|tU)s0#YU=~-fvUMaZ;lJ-cy8N%nyFNY0wd28~Xisw*p3d zn++vSywY^uWhx{TzDhdgzT%wnY`ULEqBXab4915>#r`Jck8oTmxFGsw5z6bLJndy>&RhaJ|>V3G;!zi}(DmTd(_l zd8ava#EqE0eLXC9xrSTG%s1?!+KheYnTE%ErapI~x#L#OneX1X_?78>tC^S!JN{m?BJhz1CMbx5`KrK^AqrP_WZp_c7RMVGRKmPn-++V)`by=Uu zS+?zi-xy^)W&8R&>HBWCUzit2Nu75}w1?T(BrSM5Xk*Z7=L_t~GJW)faN`T>W-BVF z&OiQ>wb4@3gSRp+dqjEB>2IUI^3W}4N%{5j3%`8&ur~1TUY$GUb>td8>{I?p``N|k zA8uT}1|6+6{)?BB=%+cSJKi+B@H3lkw=~~fPe0!={qWMm=NDhNd~%ZFYlblcPAVu2 zI9Yb9aLnL+L+pnb9e?{|-9RZ#ZRpT_r^>esw3f46)H8w%r<66S@~f7ya*>n;y4e4z zM5%(`D)FE8aE<>->hGx3qI0~D(W?r4#Y7~AzZ6TZVqWg@)sB&7ll~eVvTelfvwWSLcQ#H8&?p7+~J_4XjuEUin)Lnoe5D?gX(kmIhy zm83d6MEjOXQXP%OfuufUPzaY-Vo*r*QvW%?S)2SFHObpfjXbPWrF;T!-~-$dBCR6J zlleNtlZ*C8`J7+JlIWFs#ByRL>>8wPGoPX?Z`#@pnO@3@gY1* z2p%Q@;-U_O5ey+7`sBy>q5bqI8}f2Af{IHz(3n1aL+|paCoN)lPhGf29Z|j}6z*k2 zsgXA1>uhL`wsCcqI8EzaUc_ZQObE0A4?wuL5v4@fkf)=8vs_w1Va_O@n!;GC9{NR` zPdcVJKO>6vF_0k2$B^qXprlYME^p{9%6FDH=*+C~3+I2qiG6-XR?2}zrCCSTj4U{` zx~zQHyqua9Em2LK#qQ&35-lg@hZ#&MiXA>XH`#lbDF5$-L<$NtgB|UdlgGHCt|uzP zeGhP+u3mt$5JGTwp8x4_hSB)r`hx?1aNrLP{K0{Lg98D<7uh+z~%5Ci7BLl_1yVBYqBnh#T3^Smdu8Zzvh*3}F~d20E&wuQiwqwYvf7x@uA$bLNMIu?EJ#;|$=z>kK;? zRxw~KXlBS|2xGu^B>KW&hTeJrdVbIK6#ccuA^LSip`X^3hEaV<1l5;DGDJ~bNfgx< zhjSRoVHAxl2&2;MK*~+_rKCs~@^dpM8w+ho#-Q0yM~!J6Lb^<^uBIyKXsR$MlQxIA z2k2=ICVg%2W(e~@jVz5ds9(Q6rv~;{cw0k7@m(X0KJSmv>vP80r0@9&B|%?IsZBgv zlI-`gv$bIs6KTnSH5nC#|Hya%+MlAI(-bOl{PimH0?tLIK~$9!K*bq8 zl#}Sj-{bZa6)=MQTusQuMwifk%?&k}7Bz`x9i|PmYH9$KNmCs#NQ!GQ9}KjWX_%fe z*%&L6i@7p+^SViZ)gX#-9{6zAiePHV(V-x#em$_ME1P!CD59|}hrD=C3h}gDz^EEA z;Jq-2p&!HV850HVkLf?xAzhXEfqE6W0cR_71E_-OF3a+#qI7Sj-JMdS94RKqnu0vc z$=%L?Y%Q2}?%U91J(jl?%NBI&YAO-iq>;4|uK^8HB7Z9-3b$9LSZ8I5b5`O|iDH}v zQ53*o5JlPzq?`a{y81~mZJugLLDn+;(N3zgwljlPwx`mh>PSiqb)Wz@^Ye`8Fa|9K z=s@p&z_2>LO{{LQN{#Y-cu8`A7@ zV_McUj5bVgq@B~f>9vJn^y0iQT013(7LNC)?aQhq9?TjOPc?b0iz)7SS71(H&hRW9 z0DZr8;n`F42U_*h3AXO<&$?Nb?xQ+8H*m-+MImZu^8(a<$qUe+>R2OcPUpYT%^FUt z#s$#k$q}@7X(k?b<7v@^NH%}>r>ZP_N(nKh00*pzsz`wK*Up9*nmsl_ zl7B7JU!3B8gK6+(uwu|>z&sf`@DINkcuX0@;1FWdKRv>JPQo-CK~>S3R2!#BO$nOx>iiTsygHxuEyJ~TJ(C$k+riQZYlIY-?96GkSg#Pq=CB43`h&Ij7pyxW{Y2v70s?2nxq#$GRu^mEK zCkCC~Oe5A=5jqVUM9vn2r1f8WvjOC3txB!cVKi%uOn*(jME`B3HG~0cy2cFZ49W}` z2Zek&Dqk#D!!X-{hr{g#J&1HvqG%TtN^l*_{cs5DG4xW6^;4boRD;SRSf82xQB42X zWNn(9Z$@(}tZ8YZ3$1JOqaD*D==H@JbbMneo!nVVZ@by#DRNYvn!?ACx7&ARqE0t*I=KW^mu1(Hzh7 zD~bMlOj!&A=0g|<@h-&N_?hEisO`W#5%x+1h;&kx=#K~e?n5ZuOO47xwW%@Dm?q{8 zr#aOQw0w*=?U)%w`&VVt@vWtFVtXaMy0U=Q&B~y;ZSgd&ir;L ztEDVkK~L{c$ld|6?v^{+akfyB`vU6;?$K6JiW5y69ZORhV`x;qAK!Zr)0oW=%HYI+ zZvqVli~pX8{Ne#E8*{#VmxgnZH70C4S-efV;8p(h) zBQXX%ll~CvetXhAd9K0p4d^cTE#Zm&%Jl;$7v{T=pO825qWvfNfqRTscn*Fbzk|8l z4`jYRYC|du8qpS)L0i(e$Gkw@D33Jo3Otf=z#Vmq`h{-ezIPeW1?ZiIJg5VF1y8_Rl$XXE#%I-x0-hs8O7!RRH;9h< zphl)HiouNm^y@O<9q<(Wp*HJz*aWk4I!Q5JQfJ)g1@uJC)0SgLl~9kOIfkbyk0Q0l?fE% zzZu817)1Ynl79Ob$AMHHI)vpSzhi(8>KF2YoRKEc!*l_^C*=<##ylkyq|h z-FnY`OO)-I?{xDNv?0IXi3q_PJOeL!^G4>E3Qgg;&)A9(s?GPM%or!KGSdM4c>g;v zm@r`9K#c#7(H~_$Kt0M~0MoBVezuS1Txdtg9C7Fy=n*00BxHf-5=~4S$^ft4W$_%c zLI|2LmZL7@0gq)}VSVdWPV{jpPj}ns6B182ANmvkbxq*0zqyRpWb%CYJKT}i9kj69lGB&+zxP+Xy~R1@&^e01g=89zytZE z{?2(2N4}mi-Sr8%BgA+BdPG_92XU0a{1Nj-@E3WIhB}45pu9*!JL9TCsHr4?YI1!k zEy{r$M(AQq(34>}gB}CszxW31!|)XSan6Iz^D#6O=fyTR_Uh#4pg}IfnO4R@9-p5< z6SphrALA$V5V|4wAaoXV;W_SQSw0#wg+BMD5wr=t>fHxry^-h1s894w)Y()TKn+Fy zG&09qT7Pr4F#!FT`$wq%nO z&2+=gs5c*Avn1Vfi08093g;O$(KQ)wWtAgD1IW(bAz8Cby2)-cf<^$}o@LYu83*rIHlOR_ea<}I7Kc24$ zd5dvR^lkaw@Mx?Ryb&SzgZ?4<4|s(6IQT2|34T_PY)AEl{#23SK?$KYPL&<|U+U=M@G_!8pDc4XapfKbwx zZoc&BjlY?sBe5KYd9l5jmjU_k*y3wHlyw*1fbx6~{TzId=wbZ)FNy8lf17Y1o~R7UDk z4X=HGUf>M5Ll;1&kTc}^h#$T9(?i#z=b_!@pf}(L_#;B}9n=r|NAwl67sa7J^TOXz zU6MIyhMXaPA$Oq%_%6n`pLkDrGVi92NuXDxl>jl#Vd4m^_HRd{?8U3cWzCa&lwx&>ik~75yGW{N=GrMJvIUm;jgzi6+ z{_+T|zU496_s8-2b*wMH@49K1@ML}Mk$*RRxQEQ5nO7m*@)fuX{s?*F`J?>uI1$C= zLAQ9PpiiK0$nP8ud$o@~66~ri^$qX=V;|@heFE=I+)r&upxk&z?0+!*W}qMaUdUd| zd!9)@=TjINr~9||Tx*JBJ89qy`2&E{ll1qD2U354T)XvNlKZ3nj(kEtFdm>j)QvRo zPw+_aPV^N#>)mc_0LBd?3Sk>&u?`{ngqMvxUUu^OS9Yue(?1;hZ?l;s^!tA*d(e)n zHeUZ^N0B`x`RPfx$-2#B0k;cW#P}b~@<9I(xQh29aPG|qAxn9@>-D~5xq}ZfPi47- zHu)U^osxCy(R)W;nm$={GBwVxdHmb_?k#ci?pK%KMM+UGg-$ZVZMWY|4((F^C&d( zA1==v>BW0^S`tlY2e_h5Kpg8}Vz=$Oz~Pa+AJNcU>`kSqjxsIX^JvgFsVS&^PoC#L*7)E!r2M+;5L~9t&Ib$MeervSE z8^}f;BV=5_AH45kncjKhqN%aKQ{o-?gS?RE=prv_VyMh;p$2|lkYLCAT`rUpV@*Z8 zUy>0yqDS8Ze;*qYnTMzg&pV8* zEy0u*@rYI|oA-&!qA|IZi4$u!Bl;%s|Bg-CX=!?)tgvg7qjpsjc!Nb}1 z#ti-xdzgOE{V&lDrI?UEJaEn^FRG50+suu#p_$F$yuLoXN0+0x{ZYB@RG04|;exhn zbKE3-7vlqDjdYaHh#EmP{CqU)wj@)=Q=+B2|H`y+KVw=^24kh@bI?Iq|K)K7Asn57u(bjpHlAfX+ zG3G<=LQZmDmB%#T4cUqi`4FElGC<-ZXzBf)?>)AGcNq6T6Zj|OjrShvL_dBOPUdDm( z15J=W#xhBsd=K5nxCR=4D?-pcxjuvzwZ}?jgxrMQOZ@DXALzwB%7CxEpP>!;8Rp1_ zlKh2EfFH;&zB7u`+^8_s9dkeSM>0IhH2vmW2lPJc>L{_hHoMke@(%)kr!<7}UakYh z2bxP`e^Q7ARiryhV*q3XT1WC2hW-G&Ad8$>8!Ae&rxGq#nc*zS4t(h??vqG8oHAnZA+E8{uJPDLLLqVCz!t9O@C*J-I@6fK@{n!BeezI z!*^@P!YrD~yx2BBlhXNK$Viea<0rohk#{JgO&oc!I4$@t_&m=xFKfwp^T^=jtc`5QEt+ggjrr*)te|Mj7Ha({@;Cd6x)?`mO9ep3bv`J_92Xg3+jVu zQBycA8xut<$1^`V5^2Mf6xudDgI=1EO}l63(i`*G25Mmu9avOGhZdL9;boO<7gb3| z)>YBrbro#S#p$bxY5$5MwhJqu-HUT+*MdyiF)Nieb|ld1aWQN|6iN%Zz1bC>G_}Zu zCgj>tONJHICl8~Vcw@GU)2EU!Z7K}bq&&98%Jx&EOtzWJV7tK#ZxyyxQl^<>Qz$9I zfjk@yZ~kuLdli^k0ZjLlxJ}!0y%iM8&XNud#>FIvkXXOOH zGCMzN&)mX{(H|?bYY_f7NCe?%qB%XaB~I^kZw=lHOi1Hvav^O;I1s9Tk3l z>d4>=9cBLCjxX~1z9rA?=Y~w@yR|9yRFP;!#jzHY7j8mX!G@IPugAKgMTwqlmsa3K zEmg61dy(_MIf{4GKLas`?a4R2wPe7&uByQcx~eqhca$5 zo6}JVyN5rnKRECQ2mau|9~^js1N3{YueviUm`afc3InC^M+HSG!S4gUl;z^UH=oIV)y;;4!iO0 z`y1iF?sO5Vb>EB7wEI2?hP!iJ34dIF zaNvI#2P*QSMvN>;h8>3u1NO4SJotYZrjO8>I3`z-eR)G0E0bTX%8&jfFD)Ft7%LeX z8GIP9C;yvvSp4k2{hB%^Tam$Z%Glg-ouhNk!T-FrIGz$C+}Mr?zUO`4V5BxPEM%x) z@Mh3w_#cx=Ls3Nk=BhY{@uQN*Ol(L$(b<%Kzq2Wm>PizRHq@1U#@X-EOcQp1@E!j% zhgm?q-1z zzQfZJLhR}?V_csrO7-18GAH;d`$0c!sZOMkg)x-O=g7I)nMwZ6@PjsIzvp4>_iV|& zlkEF_fw9`hfIS`T>&;*o$q>N+8iq3TXOQsW@L##ax1<95F82xXGXEgh)123iuy)9P zJM7Es<7C8ZY8JeoY)y&b4wTKlrP&EylpgCzu_4an=Wfk*rh1Z(t^xZk>ubwC%!nJZ z->xzHe8QKT&*r+$2w^=MdbFdDqQX)&m4RJa>Z&Du6cu5kY05B|;rGa)2Y)W7P@d^) zKe8b3+lI18Y8e@e?|*74kEEKSFe*y(q2x$MUKcba#}PV`FEMb_V;^K4_D6*;t`_^@ zYH293e=2;DRlsxhPaRAnjM(1LRP`4hTcxj}JyfrFnD_m`Z+O2ulga{USzGq6rKx^@ z@pUmTW)#q`(I2qq_OHm{sj;jwH_)DaYOhFswb|^)#XhxJY|9-VV$1v4=HzUxOO|{l z0DNh6*@sy8(VFTiv9GY~N9${)Ou@G7%f&vkQS37+d}lY$a;E+3gL{02=Qc#~I$j2q zGjBq@ETLbJ0c?ey=_AJJy)V%B6#mG-zQFeE6Z>sG`(R|nxlm%59j^foBOgaSwp~>x ze;YLla~RCNCW9%(dno(#vQJ&eP$~{oqdfM3&G1qsK6g^`e~n{*j1*55Uh5jneuqQY z=WYm%&(NS*<%YDpE1u@E-|P6QaM-)v;HEL9gRL9vU4$O}mK>hKpZz-rh1m_TO!82U z%?Z|Bl^$ro>ySFU7pg@K3A~4uXGPQb{Jr_3Jb1k>jQy=+X#3Pinp5LU^>I4Xl59wA znI_a#U{15DtZ3y}SK2u>fOgIdrnQp-Xg>SQO|J2v<{~F5P8v>~^;~vrBDIYSr;;?! zpBZQP>A+75o_^^+QGjv*@OM ztS_UT3v*~$S29g)ilot{e(dXR!}c)RlARpz0*;bRwq!3V+s?sm61GxO*qsMM=a!ClG2kXb1cwqu75tiE+*k(WY9~i_RizTEafPJ7z@E z^K%nu{j@k**cQS2gF(E<&wU`;lEOTMk05ZA@dCcUL$U#dO;b0Huw{~Ik!_lA4;#SV zbf8>8q67Op#!@@$PjRZ`@0ZAU_tqi2570-Yt29RYP-BJ>jmbBsmI6x}oj-zo{H&;y z*W;6U{WQ>NsANZo_P{T+0b4`>a2EJV_E-EId`6mNr^wF*9Vmx7fUlhPhz{713!BX> zwt1M=6eH;m<4=raIs@hv<_vhBi9Wzl1%-HbrPaB9u!ENUUs1PcOU75Wy#`JI*bO2b z`G70vKq&0zK*u9mWgG>aaz5F<8u&{3!}(!jgfa-@{EcbWxFp7(-!JTM$o_WujHW*W z`T%?_9>bq~%qC`fDY1WrjGwUgMt!i|K`7zOc=p5@cbV_94&Zrj{KeUtNE5h09-=(T z3j9R~xgbw~lR7Qz$l&oaj0%z@f4K_A8GU#J1AJv*JJq8<>?2m1#y*0<4l*xA+h|MD z0fB!vzXkunOMr}@ECaz$At%T}q@gaP1EjQW{tNu2u$xDVI&M^JOls0H^jkf#C!5{8t?&*Nb9XD&~c>oZbRrj z(qK=Ga_zMd{2mEpe=#RMUq`)~@x}OwdC)WG(@Ad1H#2>Q$YTlDBjNR!F3EUcT#{)K zK4abb!DVFp(U0ZvQPk0+E6i(2pU{ucMmK%P4;rCALN8k?f~m1MK=$`C*FyibXE0!R z<~L1}yUMvDK93`m_o^kETDB#{8MZiQ7xwrb;2XDxHlYs!C*Umj2^@fz=o3OF7!Mxx zb6MvF?%;=@N#KwB`XWE7V}E7%YuOLiEoZzj_Fx|U)ccpy6p}qu4wr>%OZ)1u84z{@ zunPcSFI=)Y;{EU-_Py|D`)ObH)p6sqR|Niocc1}riLcNV(A}Meu=jW>j~9=0Oq9bM z2tFriQTF6&t6#+^nlV84#diQlA6==QDw`@Jbr^rxyvz2Tz**ogY#anF!mbJF(mp@i zWcjd<4SciUmnHRC##P8fl3O=T0!JBlS?|!dzz5Nf%QId1OcA#CjIbjw2LtFobO+x6 zkBvQo0^V<)ULB*y=Q_wX`@jhxWYHV{XT_0EwufNaxg2a`a3-@C`wYQ927OYdNz5G{ zg`!V^MvT`8i&LGbEW=&$cVc@#jQ<$-p*xSweFXl6ff}`S32Zm$E88FfN9c=$Kg;7; zI71fCN(bFYhmD7@{Rw4yWStw@qgz4_;JX-4h1~MuZK*WfUGi7*cQpq7;5~GwA4AXB z$#Ll_4cAI;N?|)Jw$BF60)NCP8ZLf)GMR|Z&|-&TS~-*Oe9-c$dl^}a?_(A z_H{$wk^9J_u?(~zEhUU?!B~G1L)qWP%>?+v-d@amp2EK(M%#UC_Hat(GlI~D;2+|> z`6-?OHwkCvvlN%|$#!Bw?~smq5K3vB2W13JunEFg=gHrlLchdV5ar9~r?bCge6SVU zjG00IF=qhppZRTD6Q`@+mS@dAg0gLxzybXfIN%<#K-eRT?t9=T&Z08 z1ZkiLcFtb5L!~}~e(mq5L5-!s?C&yy@i%RJg7;7Hzb?s0d18^n&D>CZd7Ol-xo*K@ z@Lh^?y5J?~01iSXpaJ+qvrQN5fng5_`#3;8+cU$~3(ujC5=~rQ(1uWq&pzDey|~Xe zm4{0H3IT4$)(Ayht)Fa=^>BtkrV^2-~k&#=ty<8D>W5*b*IbvAl`GZ zV-q+7KS1w(40%fSmfiG2ml{ihD2(mBeVh#D{ww%TEVNnBRqD!idxny2JM==dl^klx z-|K8Y&o~2j*s%(`Z0L1uF5B0#Eih=4^&7g@-5*%DQBLR#=m5T=9|-61VXhJM?@!4O{ckl#tOZ;Oz5r>SRYmd^O?w`ny=a1pfGt*X$h)xA(^Lx8jVy#r(#AhqG$^ zX!fW8n#=1{b0i3%S))Q|I{UgzuMVOqm44J&=0g*Ty=Yv42est6Qe(Cg)u!4~RT8fo z#SWu_NK>}IGp6hiL&^x!qg3{tPw~^HBwsB`U|T%cX+E;m)Fxr430qCrR|9Zf1J50R z|0}mun{`ezS3E>b2)*WdF!E znLocVzwj3Scg5ciEv~qCctzFyBWtT39DzM1+hQJERYLog7qJ~?9-k$cNn0i-(;BvA zUBWh)^G5p8v=V-&)R^hRb+m-HrZ^(E{g49k>`BepuaB+Gc#s<7#Xe-xf4squbQMDtgFVCV!h`KVbQo+Ij2QGi?DS0n-At|d zYJpCAIli9#^S+% zv#ele@Q*HuSL_RDnGkAwJ2A|j_u?HWIl_t3qFwo%Zf8Cx#(~0oZOF~uoX^+S;4|6z z+;s+o27LB9&Ry45SH3i`pTaRsRmFW?Hrg+yhP%wt(NJ~fhGDPqkG>asWX1Ljp;dW7 zx2y63C7XtnNIs+6-HdF8X-T#W+BoxFOPS2{l*rbE_w0u8z7?3bAsTvuj#-{m&p-+}c` zthY(+^Etlme1`E4QGAAaqT67~@f}LFG5XY=XF<<3xYCv>;q12*O)ENLXzrK@_FMI% zD)!w>2{k7l-sczV$XF+n*DJARi9H#4zYO2+IAgdX)B9I$Glao}L773~bym>OiDfam zRGn%}O*xh{rqGt^b8Pt>*%6cwz-w20mWfyc73;ZZM*yCQbc7-<_Sq5w`Al9u=e8ot zo8JryaSTERQv0kcrHOowC)OsVwQ#N*YpsG7tm}(9MVs<7ncki>Zd;`H<^|3mnaO9& zF#Xu?&E)oN8HO@QeKFLgUt|)uFV)jihrACZ>gj2N@dA!d;wiWLXg>n?@*2LpemrM< z3a@#4;e1oyps1w1WpL2@Hxx8 z5zOa{Div_sHVi%V^B$jCCi|gz@E*OWPlQsv-F1sJva8oJDm4NM4jLR_>4M*K8SXa_K4oc@dj_Oeh-~NdDMsf z!h&QsGBZ?9<93Z1u;0+r|MLQdo=fnPeeJ{h9z zC-JMv^QOE67alvcQ@CAS2CP~4v|k*ieJF|7*Ja;WtmDdi16V`AT8Ol+!Xefhg5C9` z{R-*Kw%&O3>U%Pd%$II`F3)hI>^LWKvDQuIb|HK0we+-K5vjj1BM83i^7!rrA-1bxRqv|-l znhI%sT3$m3pL^3PWbkBrf(HU;tQ83!Vx8H`M&5VM zdg$(n%llRNiTwX2ftEO5qKKP&jCQm?A>XFYlycW!V%cvU^x>=u(N12R?Ne!@ElKX& z7I-h|Os{r@+@KRF;Z{6{vxALp3EF$sHLKS968_^A>%zbRAn732iFVQ>M#yR1_mA3^ z+ZX(oc_8yb?nAt0$^6OY^ObqM4s+3GUi0ex-fGEn<~2h%YRPw}(Rm)!nBz_jy!Kzq zx=_V?9A!y%R1{}Ld6B~?Gt`vQf{pqALkuW^_cr5wb@>b~U5e#3R;;ta=U!Sb<~8F8 zKIbkw!42)>yWp7@uMcKVsq&gOuP$)TlIFM+v3Xkhx>slMU$HMNdg0KLidT=U ztlE2I{m3JS*Ove3z{=87yO$JvxN~Oa*|p;nzFgc8`t^(opR42ZTz+auv%XUqYyKzy;n`_+2@o0274_ISMh;mdpL-KzTPzKi#O zs`u(%61ma0$;*p4>T)OQfVNTpCea6I3ku@gww^+o?k$8KOQTs#;wWDiN^9MX)R%6d@y-J3 zOS8~OLl*U>TWQFVO7oAkqt8m2+7Q~;QBUp3F*MkoM{Oz5)CRr3HiK5)T%fV33R=7} zNU5q|ns2S6`UDeox8&exrh1#1>QL{fPN&x5B$~f8NK4Db z{i(lh2j!S_5Is#l(@&k#m6T)DQ7%Lu;7486m6T@CQkp&zM~Gfa8h>AEuX0dgq=pih zXf+h>t0Z$+7|Ff8AzmcKm*>Yn{_&=p`$zSUSK#Yi0k<#Gz~JEE5QL*)H@EJd-oCzG zj(U3f-P~H++B@3X+B!Si+S@w2+}vvG>Khb|b#+bkO-;=$Zf+HhN=22zv7@@$;c(Qr zx#i~ND+&sWic3n%^6ceqZiz|Bij>r}^o-1`?4%qwH*<81!eWh$v&P5StO;&zYK>MA zsncr=Q96y$9HIzSgoQ_hhlfX~+}xxxxxz;&^Y!x&@RtR;xo!9G6bQXMJ-kI? zk%z?1?c3kkvgJElz60K}^*h_#+`jQm(6<s#M+|Kg{0TX16&;BO~v?C0lM1$WU? zF^B&S2tRTB!d>j;QZ`zg3j6hQglPh^1SSd05sZ0#Q;A+Mn>{$fbc5LjlMUt?rtqvs z3#YSorn4D{BTQeIy)b!U?!vT=*^8^{FomI!l|~(=GB%TOgsBiSAtpkAF%_aj74spc zLyirog4xW-5vE$qw3ujt#8iu!785PzSxmE-WiiR37t<`8WjVrBj+q=2Iq;auF_U8= z$2^W{9J4qkam?WWuvwfVED=~Cus{HhB?2o176_~lP_RNk!5RUbtr8qz>A}i_g$H;n zJy?0L@Sp`t4^|#jp=0@Bs}Dz5%CM4QAp;&u8A>c>Sj(`Kaivpds~SgGCb3FlkpvP; zBvwdNu|{Hv#0rT85+z#LD#;O+U#z}Ze6jXo>BY(m9W7XXvHC6)Ca|)=##UgCu!Lg; z#{v%K6_gtaYb;?^wz6}CM*utlJmRx1omWtD3VS;E&FOdXI}5^TQz5SBnT2nm;v(ns z%;xGhP+`sN=lIQUx{=Up3;6^H$Uoehf^;GZGfODk0*RGUgjGuFXbEXd5QCVsY7uDy zarA-6MWmI9NF@_fm|RMsJ_-s^`cNo-N#TCJq`@~{7wAX&Ab&E329YT|n9Sj!6de&x z(W(fts3Ry&6;282FiM1^XhJDHGK{itXS2*dr_yDrR`BRJyk`O>K zNvNj>P;3_Za)Kx!F9ZTRc@dPHqoR~7HKk-|C^a>bQWN!*W{aYQAeGf zI_t}+yP<-5njF;ETt$5?JE*_4ng-fxXt1r8hB|6#q_d93x*BLFp7|zvnrNyQ&yh^} zT4<)XndZ71XtA@F_P1BjdTTiyZY!tbt#&%qRz|1W>~yBxPN&<;=~PDro#?8>vt>Q4 z4>r^4NINZ$cGB`#7cGx>(|*X(co*%3>>lf+MaaT)blsef$8u@Wes-?vn@UrKb+j z_bwi$`%fRHm!CO8uU+w{eemK%`tYS^>Cf+9 zp^sj|LTYIKmPmQ(f|7UAJb2M@)P>$Pk%~3``ORv=Rf~B{qsNnGyTiI{0sf-zy2%z z+rRxA{rkWFJ176~AOAtW3vs>6xaNQ_J%;=Hel=lbY*U3fDb%Heg@xh|9DJ;)^dhY2ZQ{R=S;OAGAIF^u>$I%VAH4T?ji6cHqE)QwJ^-9XQZ(pY@Mte!p;e zd1Yy@eW!ht{ee!6KG!)qT5vxti0DAp_lvqZ+uK@Oo4-h0|9aMkCGHZLw@fD5#NINA zdo$O+n*Cv^d!#m5qmEK`EB%LrCG}Pu*^LvIW8(H&S(V3f}tCd*mxDuzMLPF zxocF$pa4_Av9r}E15ANI#t1d*$J5sS+#lH8RY9fziC6Nu>a!A?MB*g@B*MMq$_{&_s?{mPPA>ir_fBzZ*TO6`3roN+kKSVl|1`;_ytk(J83$i zD}@*z=I`mZ(Fx^?{a^aaXnx4XUoHBJ`ntNh%1Vc$++J2zT2fr(qIX&UwW23DdXmvo z7cPSEby{0LFg`xc`mYxq1mQ~uLeu!j$nenMKyP;^i1pvvGyjz|okMi*){U>EE7M=< z_~yn1e#zh5^n26Ux!LEb&k?KTkApHAimMp6&-4vA)rAv&|M)$E&u=n7(-I=X(=f`1C7vy|@o9XRN zk28Jr@|C{ovSW**N9IQk&kh~j)xSQ~yE@Trjto08H-d6~W)$W82x~#fGySv@%Ifq) zS#~nt(&8w&e(oUbN4f0J^>t^!{wr5Yvl3S)dscRK?H}*hH`=y$7!RsB^L?zG>Sg7m ztAxTc>_fS5^k`2*HQ!Q{mB`yS1v~v;80g82H+}rd)w1lw{w8~0LupT4aaT=oM|E*) zb#cpY&b|l2uciR{G|#5s6tXx!cw*2=>~PcHy+uK3v=3E8R^SSivHx)>yE-qIFOUB zN=XS#D+@_V2uzF*NG$ZX#rq}1`$Itqj^Cs(Ktf<@X>e*vNLqS?((RFbTZGg8+DKns zQVbqeD~qzQ3!b74M_0Tpz!KsY9jJ`4_?QEHnvOaq-XADwNP*6`@Je)$60kU1Kzu|{ zqBc~{U7s7=_b18q{(o?+FF)A=`&Gr+TZn9$5KBlvjMdlZ?_*HPqRg`7RNeI3BgOqm zJKyTpD`koK5h%e?CK&_x;f%_dVE@>NU?FG!9%nyA?c85DGTvX1V*TX7%^fAVctwp* z2#SvNGw1o}%`%-)qDvPim1$=`7`2oK)*LL3&kG-Tqum(qliO<5XNq-3soo?5*c_|0 z+5+(P!2NxJv!AXG;qUM9iT=XW*iZlTW_2lhV~+_9Gz2JgW`$ZIjgW~W^rE-~_3XoO zm0lDf6@^Ph)|{{?bwJ&cz4LlQa<)Mw7wb%Noxjo)67X%#{!5(wOs#YO;<1UrqO>@? z7}S*I!M-`zPwlJF7^UGdQHaV|GYjBwB>pMBma~+2$P~000(|B~jsG#sik<%6f&h)c&)eJ23yPP&NE9d* z103d~V6Xq2{nwsm_6zjR{hB9s4RQ8w*OeCnU4mq1-S18J zTyGw{)v1(<0`($)skc(%?Wgk&KvgCVG0DRH6q+EX{WmW$`$Y!l{?1b~LnWCBcqyx| zD1v=+La^5AtIG8WHOYdF(vVC^P?W?{7MZu0s7nnDGDt!)Bq(_$*dPTAV0DaAhb;%r z|F^ClhW*kgr~Qj_!<+3JHDQ_%f0e~I*iRX#R0J920Y35or98;Q%1w$4EdT%(Zt)Ed z^4D+^4zB+@*N?$|naOD%ufdp^KYQ(VgQJ-FuT^Qn0wQC5!~B&Yz6ux#=FEng6~VrW zKwm{L6eSv!=mH?rUm0fc4GZ$qhOr3~_8;Cn3H#+Hyk#)DG(W=ZzwWfpH~!Wo?7w^a z6zp&8mt9#HDa%g!?Dad1l_mHH4UQt*2;6IYo$!stkD|IH7mG_(Q8p&Piu`nYZdzFm z9wbtWzJlModj|F^qn-X=TV(c6Eblt8fBHDb$CjoT@0&cjZ{o<_i6eV<9^Ny4X!qEm z#nFQcBM0V(*XM@TW(HPv^)FBLE=_jt+u6BitZi|)Wp1!#roUyXzXkSp#NaK95w;#+ ze{p9IcwxMo@mSY9c(ikFv}10hV|KWGW~gn~VC(c?%hW*gWM9)nZ^O=>`mwIs(a!4O z_Nu{FM}M=Ux53fX;OOKS_G?`BZ|xm_qOay`yZv{_2g{Q?67Uwm=*7c(aEhC|M}LQW zX|ijzG?BOeUs^8w0lcRe@d=wC8~dqPMmET~pUMtj6c^?jZf@l9t#6TF`&JSNwvj-% zjfCFY$xE=EygfZgEbt_W(37M>0b-N_l0%fhhvZD=@YmK5DNH!!7ap018GnFRBP)V|tiZf!VFgu%d(2Ly=5shWY3@$dp0$eTIx6SG}FOA$<+yG*n+fqYafb(zJsHTd+6Vg1y;R?9F0-cDTKcMzKFT-c^tN*#_*- zHWD6;X|j(=3r#WUZ>5=mcA6XP_?*n6zBtrD%Y&_SXrPG>4>Z%^!4^6++(rkm_qsOG zLu*rgv_9QW>$?VMeRhD><_BqI-vG^?=%=xZebjrqm%3i;q0aC1P~ZJN8hLq;CSDq% zncE|@a&DXs9h{&e%M)~TFO!{w>5-1^o229Wrs%}d6rEg}rc*ecMc+B>yPlsLq9-61 zuowFb_Gm9-@Adk=3A(jBMR!(qJ(ATKx&^thHbd8#tk2Tb^*OqFaGtInS){8+_t4ej z`{?S4CAxZYKV5rlnXaE&p&O@HxxLw&*q^<5?f@sZaJ+l|0KMqkqrHFO5WV{J5qj|K zQF`t2aeCv*NqY0zDSG?H8G7gDf-k=|R_Xhp>OE>7F`#0$0S0HRZ_f_oSK5*{gVjmYvE@9cCAHH#ye)RSW^w;md zOn>+1Z_xkz(FgRu|MoNb$G`tOL_~i<|MzGAK<>XODYyP6ol{+vbd3=B;jFB*^z^JOCXCXUfYPC*p*0-`=nTQ(`_eLsdY8`Md+x@W z(?^f2@87#;ZhCrZa&mMOTUmX5{R0CIM^$-AVNO=I#tZiQva>TvhL1jf@4545jvhU* zyl>Cq9FHI6@eW62RcT>vRyL3C&B@8h1{G!aD+~IVwetQUP=C3@F)%Pxp!Clu%+3ZT zCnv+(-F;yg8uXmv44=$_US}wt56Jf-G(V8(lTpk};*a5XPv#V??O)ovXV2oVp@N(Y zF~jE;Jp6ArKK|?cMRy?5V!`>i)$fBoLQdv`xiN8dePkn6&q`^k|T=N~_J_Vnq~ zM?puvNST>O_WWRl$M2oWEqMGNrcR$abqvV;`zumE$NTp`{Z!4_iqv7?^D-pv?)#>S zfUnwxYmSRPIa${KIi8#xAMJf-x}XC1B8K0;i{Z-|nr&r&DLMK_%QxfC|6|4DaQ`em z0P_lW`IpIsUxoeiKdsyn5n+k=YT2^R;ic~GF1$u#(|ol&!XKG|{eN<7vDuPrHd`Eo z9bMwAC-V4A*grZ`oX_ygwptyFb1-4&;&e6N#^H;d_~IK3uZ~rRgv7G`%@V@3X?T1V z>>rz{27Z9yLqkKY5GNjE`MOoDcH*;T9KPhn&jz-{TFn-#CE8-On#V7V$62jbCT6R} zVzydiIs4VQkMN`pvIYeOSs=-m?9V2vgEs1DSJV2(D+N4$wwl>TLL9?F0#hypT}m0Z zJL__Gbm8Uj$Au5H$mMcNU?A`T$(9U_{enF((4tVtEdc>RwEhXR5By`ZHKjLyHt24# zm@G!4$zrjjT!PQ`WV7Sh3l@`+Z*yP&bfut%!_U>0UjILX?h3h4E|)>%$(Ixgqdg_% znF}edHii58XDbD@9R65c=`G;pa-&QtHOgeb%g2-Ca;qIzA|a^aRm&FH@V!s;yv1Uj#ct7wafBGWyu5Ify08DmNPx9gUE~d!|Cqpf9=G- zc)YRvF8tZL)qsV`!zr6}*2du*tApI#UHD(K?lJpLd{g<||2quA9FC-^0T42uDl5xB zPrx@Z``z<9Z@zx-x#ymH{(0b=H}IH?@7%d_ z>(;I7H@V=*c@So>GiUe-cztbcZDpmPh2j6?cuP5(l-ab*1z|9?p?i60-(IW9feJf6oWo0BvgXk8;<%L8=K0?ul9uN8-FG27@sa{vevdXrQUF*~!22p_sx#r7nL4o10q8?HSA;J?E94fsF>VR3zAbb?mpTB6~BpS7bY5!dzsS z#e|Ewm~fOcCR~vamtl;8|9xC&4-mj6Crgn!t$ISe>aD3kzcb+=7IE4L>JLlGKpIy6s zX7%Rj@x>uFRso$wLE)%dG_4$?CIs%lfMZsjCLX% z%}1Vd%tmW?nB3*hSZhB^gV^+o7Tv}A z-o#u!a-Lw;A#A?kPkxLsUKOUm4lPGJ+nRf-DvDxEh|;gk4j|B7o|`<>Y#(SU>u)IQ ztt;!PE$gZ+>u_;lhHXb_4ys>A;YXGB+UskITJ!VyNPB9Wu{1Y%!yla5rVdx&KU_GP zY;W$bswlCT5Y=Cs9sKx}Yb9BUz0GV^>2?L)+ke~GJHk7gxx6rahdl=^2>WmNQ(`eD zs>6L;{_JXR9;kMd#hNnXObEOnP+yvzdSrI=@XY9;UBic_hYm~)tWWf>?d)3}?^z!0 z+CSX6Z?JREK=lnqD>~G5({*+lwNt$q_%b%IfmZ2I)d7L>b-h^1tC$C;ZxJiV- znnYj{38J+uN5ClbFbcODH6BK9#s*YXNEUFinI#T*7`+%fbyS5OW?+zOzzspW3AqMd zo@TKC#_=gO{3(w$rD!9R*xl!7wyR~N#^H!JBa4Ca=Q<)_2=&^6m9{`-g4HKJKoQ4S z9&h0lR@$68dVS(8K5-}mxN;Nb^LU^5K(G>KVSKYcICYvf!q?@`d{^sOjbjJ=NiZQ? z_Q`|m<@xDIe2BLyW39^g9A#{bkJX|8$7LyEqZP3huupuB588QVx`pEyt{pn-Qp9H~ ztkG;BI6fNyB{)7#3FDjn*37=Kx`pUmthi;0#+L-&`V#S$Zr32?Fnm<=86{@f72V%R{QEip1!V+I3#zHq;4 z5~4G8Du1!lpWQue6ZMt#2{E~e(TFI*A4fqZhQtK;MEfbCqvd8_nOP|_DP_?}J%G+w z&f5KWR>VXr7}8H+=J9CvWgKm019^@%%Q+0ZQhvdoy2R*g{Ud+&^|npdS2iZaAj{*> z;@GE1^eD{2v!mHxVZ^D;vMA&ZD5YSdNeZ23w4;~jO}doVd5noAXt04`=uWV|0uMTy z?^k1DOs+u{fJhZbOTFzg4VBHwF?q=`hj))5u>y%F+wrfLF><3(W=xkEjPOLFH%g+? zB+#Sal}T#MkX7x;LlR2WLY^s8W`uhjLys~dRfNY#4JHg>Y|MZWhKY`m!#Mo8=~^$? zsiV|^5~n}QeeJW2Rc$F2WT_n9Jq~~PL=}UdOz$I&GD;&Al1RB&D;Mjd#5#optXD`A z@*}3+9?r-$BWVRX%UJPY3_M2ZzzXI@q@0Zf!!fjjkg}kDo{eWVj_4JO-l z)w9I~HA$!O0S2s#5(BToSmdNcVIT}jbV?c0QgD5qclpziYArIVgIw2VeV~1@ zc}G{8r6ARcP&pDwkZAJ_BCS%YR*2O`W-vk~3X_S{28l{8Lc$B$6YSbu?~Fz$BvwmA zq)}#$3^s%)^J|hiZ#HC=S&=)Vl1nvF7$^ysiIM7}hK__9g&1aG9R9rM@~11!T4K@! zOP%-Yz(B{|mL2#XqJq@eBYSru@q|yz(HJE#qDm8~4B`kRtr$eARHmz<#Of$XLKBjJ z#?(fs$|zE&OH*simb?gEys~sYefVKd=k-Pv97tuOcvh!k6ugpXjF^6yKQFob>CK2O zi`Im={5dq(vD8}KpAlP_7K^aiXRqC=DP@T~;WBBcR2;4s2T72~1NIJy6fqqv6~&im zku(&7t{6j6+rt5*(O6Tw+nMOdQDB3=(_$i;#Nb6{Hmeh=ni?uVPEINY4q9 ziYoUO>5>DWfTPS|sZEvuiHPT*NN@a#14Le6=z$Uu7-o5YUODf49vjMxtAIZ;=lwc1 z(z()BGm;gDEF^>y5jCqVV~I$}&GCb^NN=nxN|6xkrxn60R57z(+0cOAtU;qN)`JXUeAD80@@SKk-_BaF&cA84DR6B^aU2sY)Oc3Pb`=k%y-g_L&a$kg5e@Zvi$X z#5lX!Q|u)adkc|C!P+^1Na!KKSf+!wOH}woLZn&9xaSJ^^VSuoKR9(=Y$Rqj{(hYs z?>gFDJ5!K=tghp{KV0INT&=F>h)9Lm1~cIm#>}NkAw~6ZCp9N@AC1zmyhkabaeN#M;4zsyztDS z`KJ%gUReLg<6X%!4&+QvMyJzI|;>i1V&hY-=)a?oSNZ0kbIMs7@pkaSW zBA>O#r|fYhm$k=o_mH^9a`&*>Zlv$w$<39)w<(Elc5roOV0Bmj%5>lIR1Zt#o9Nm* z&i48iM_Lw!TIL2=LfgLkbyV3ZCQO@D~kh0_r zYYgwQgCS_&Jg^(NTrPhuP4_-A(6C;Xv~FjZ^|EB}n%z~kvnt=q%1z8;Fp6U*42^5R zqmeVhpVVm_rg$&|@OV}N)5H8>&qbiiyLz7-Y&gKc$p`F797AEuwQO!gud~Yq<6Bs{ zY4~O%d>0Sn$2xoA8)uDGdy^kspL=U_&mUa8yE^mhc-P%kFb~^Me)Xs?z&5J9vQeEm xQJ Date: Sun, 25 Sep 2011 08:32:03 +0200 Subject: [PATCH 103/207] fix console rect when resizing edge is top or left --- ConsoleHook/ConsoleHandler.cpp | 47 ++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index e695ea3b..1e38bde6 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -304,13 +304,13 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD { if ((csbi.srWindow.Top == 0) || (csbi.srWindow.Bottom - static_cast(dwRows - 1) <= 0)) { - srConsoleRect.Top = 0; - srConsoleRect.Bottom= static_cast(dwRows - 1); + srConsoleRect.Top = 0; + srConsoleRect.Bottom = static_cast(dwRows - 1); } else { - srConsoleRect.Top = csbi.srWindow.Bottom - static_cast(dwRows); - srConsoleRect.Bottom= csbi.srWindow.Bottom; + srConsoleRect.Top = csbi.srWindow.Bottom - static_cast(dwRows - 1); + srConsoleRect.Bottom = csbi.srWindow.Bottom; } break; @@ -322,13 +322,13 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD { if ((m_consoleParams->dwBufferRows > 0) && (csbi.srWindow.Top + static_cast(dwRows) > static_cast(m_consoleParams->dwBufferRows))) { - srConsoleRect.Top = static_cast(m_consoleParams->dwBufferRows - dwRows); - srConsoleRect.Bottom= static_cast(m_consoleParams->dwBufferRows - 1); + srConsoleRect.Top = static_cast(m_consoleParams->dwBufferRows - dwRows); + srConsoleRect.Bottom = static_cast(m_consoleParams->dwBufferRows - 1); } else { - srConsoleRect.Top = csbi.srWindow.Top; - srConsoleRect.Bottom= csbi.srWindow.Top + static_cast(dwRows - 1); + srConsoleRect.Top = csbi.srWindow.Top; + srConsoleRect.Bottom = csbi.srWindow.Top + static_cast(dwRows - 1); } break; @@ -336,8 +336,8 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD default : { - srConsoleRect.Top = csbi.srWindow.Top; - srConsoleRect.Bottom= csbi.srWindow.Top + static_cast(dwRows - 1); + srConsoleRect.Top = csbi.srWindow.Top; + srConsoleRect.Bottom = csbi.srWindow.Top + static_cast(dwRows - 1); } } @@ -350,13 +350,13 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD { if ((csbi.srWindow.Left == 0) || (csbi.srWindow.Right - static_cast(dwColumns - 1) <= 0)) { - srConsoleRect.Left = 0; - srConsoleRect.Right = static_cast(dwColumns - 1); + srConsoleRect.Left = 0; + srConsoleRect.Right = static_cast(dwColumns - 1); } else { - srConsoleRect.Left = csbi.srWindow.Right - static_cast(dwColumns); - srConsoleRect.Right = csbi.srWindow.Right; + srConsoleRect.Left = csbi.srWindow.Right - static_cast(dwColumns - 1); + srConsoleRect.Right = csbi.srWindow.Right; } break; @@ -368,13 +368,13 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD { if ((m_consoleParams->dwBufferColumns != 0) && (csbi.srWindow.Left + static_cast(dwColumns) > static_cast(m_consoleParams->dwBufferColumns))) { - srConsoleRect.Left = static_cast(m_consoleParams->dwBufferColumns - dwColumns); - srConsoleRect.Right = static_cast(m_consoleParams->dwBufferColumns - 1); + srConsoleRect.Left = static_cast(m_consoleParams->dwBufferColumns - dwColumns); + srConsoleRect.Right = static_cast(m_consoleParams->dwBufferColumns - 1); } else { - srConsoleRect.Left = csbi.srWindow.Left; - srConsoleRect.Right = csbi.srWindow.Left + static_cast(dwColumns - 1); + srConsoleRect.Left = csbi.srWindow.Left; + srConsoleRect.Right = csbi.srWindow.Left + static_cast(dwColumns - 1); } break; @@ -382,8 +382,8 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD default : { - srConsoleRect.Left = csbi.srWindow.Left; - srConsoleRect.Right = csbi.srWindow.Left + static_cast(dwColumns - 1); + srConsoleRect.Left = csbi.srWindow.Left; + srConsoleRect.Right = csbi.srWindow.Left + static_cast(dwColumns - 1); } } @@ -438,8 +438,11 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD ::GetConsoleScreenBufferInfo(hStdOut, &csbi); - dwColumns = csbi.srWindow.Right - csbi.srWindow.Left + 1; - dwRows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + dwColumns = csbi.srWindow.Right - csbi.srWindow.Left + 1; + dwRows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + + TRACE(L"Columns: %i\n", dwColumns); + TRACE(L"Rows: %i\n", dwRows); // TRACE(L"console buffer size: %ix%i\n", csbi.dwSize.X, csbi.dwSize.Y); // TRACE(L"console rect: %ix%i - %ix%i\n", csbi.srWindow.Left, csbi.srWindow.Top, csbi.srWindow.Right, csbi.srWindow.Bottom); From d893f893d3da8835eee2b82f08aebb26ac81a102 Mon Sep 17 00:00:00 2001 From: cbucher Date: Sun, 25 Sep 2011 20:23:16 +0200 Subject: [PATCH 104/207] if the cursor is visible before resizing then the cursor is visible after resizing ! --- ConsoleHook/ConsoleHandler.cpp | 44 +++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/ConsoleHook/ConsoleHandler.cpp b/ConsoleHook/ConsoleHandler.cpp index 1e38bde6..23b2619d 100644 --- a/ConsoleHook/ConsoleHandler.cpp +++ b/ConsoleHook/ConsoleHandler.cpp @@ -258,7 +258,13 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD ::GetConsoleScreenBufferInfo(hStdOut, &csbi); TRACE(L"Console size: %ix%i\n", csbi.dwSize.X, csbi.dwSize.Y); TRACE(L"Old win pos: %ix%i - %ix%i\n", csbi.srWindow.Left, csbi.srWindow.Top, csbi.srWindow.Right, csbi.srWindow.Bottom); - + + bool boolCursorVisible = + csbi.dwCursorPosition.X >= csbi.srWindow.Left && + csbi.dwCursorPosition.X <= csbi.srWindow.Right && + csbi.dwCursorPosition.Y >= csbi.srWindow.Top && + csbi.dwCursorPosition.Y <= csbi.srWindow.Bottom; + // check against max size TRACE(L"Columns: %i\n", dwColumns); TRACE(L"Max columns: %i\n", m_consoleParams->dwMaxColumns); @@ -266,6 +272,10 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD TRACE(L"Rows: %i\n", dwRows); TRACE(L"Max rows: %i\n", m_consoleParams->dwMaxRows); + TRACE(L"Cursor X: %i\n", csbi.dwCursorPosition.X); + TRACE(L"Cursor Y: %i\n", csbi.dwCursorPosition.Y); + TRACE(L"boolCursorVisible: %s\n", boolCursorVisible? L"true" : L"false"); + if (dwColumns > m_consoleParams->dwMaxColumns) dwColumns = m_consoleParams->dwMaxColumns; if (dwRows > m_consoleParams->dwMaxRows) dwRows = m_consoleParams->dwMaxRows; @@ -341,6 +351,22 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD } } + if( boolCursorVisible && + ( csbi.dwCursorPosition.Y < srConsoleRect.Top || + csbi.dwCursorPosition.Y > srConsoleRect.Bottom ) ) + { + if( csbi.dwCursorPosition.Y < static_cast(dwRows) ) + { + srConsoleRect.Top = 0; + srConsoleRect.Bottom = static_cast(dwRows - 1); + } + else + { + srConsoleRect.Top = csbi.dwCursorPosition.Y - static_cast(dwRows - 1); + srConsoleRect.Bottom = csbi.dwCursorPosition.Y; + } + } + // horizontal size switch (dwResizeWindowEdge) { @@ -387,6 +413,22 @@ void ConsoleHandler::ResizeConsoleWindow(HANDLE hStdOut, DWORD& dwColumns, DWORD } } + if( boolCursorVisible && + ( csbi.dwCursorPosition.X < srConsoleRect.Left || + csbi.dwCursorPosition.X > srConsoleRect.Right ) ) + { + if( csbi.dwCursorPosition.X < static_cast(dwColumns) ) + { + srConsoleRect.Left = 0; + srConsoleRect.Right = static_cast(dwColumns - 1); + } + else + { + srConsoleRect.Left = csbi.dwCursorPosition.X - static_cast(dwColumns - 1); + srConsoleRect.Right = csbi.dwCursorPosition.X; + } + } + TRACE(L"New win pos: %ix%i - %ix%i\n", srConsoleRect.Left, srConsoleRect.Top, srConsoleRect.Right, srConsoleRect.Bottom); TRACE(L"Buffer size: %ix%i\n", coordBufferSize.X, coordBufferSize.Y); From 3e0746a603739bba20da43c8200127c140b5dc3f Mon Sep 17 00:00:00 2001 From: cbucher Date: Mon, 26 Sep 2011 15:46:42 +0200 Subject: [PATCH 105/207] AppActive status is set to all views of the tab when grouping is enabled --- Console/TabView.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Console/TabView.cpp b/Console/TabView.cpp index e3646f2d..43c2be18 100644 --- a/Console/TabView.cpp +++ b/Console/TabView.cpp @@ -304,10 +304,20 @@ void TabView::SetAppActiveStatus(bool bAppActive) MutexLock viewMapLock(m_viewsMutex); if( bAppActive ) { - shared_ptr consoleView = this->GetActiveConsole(_T(__FUNCTION__)); - for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + if( this->m_boolIsGrouped ) + { + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetAppActiveStatus(true); + } + } + else { - it->second->SetAppActiveStatus(it->second == consoleView); + shared_ptr consoleView = this->GetActiveConsole(_T(__FUNCTION__)); + for (ConsoleViewMap::iterator it = m_views.begin(); it != m_views.end(); ++it) + { + it->second->SetAppActiveStatus(it->second == consoleView); + } } } else @@ -498,4 +508,5 @@ void TabView::Group(bool b) it->second->Group(b); } m_boolIsGrouped = b; + SetAppActiveStatus(true); } \ No newline at end of file From 21dc7aed422e0618f930d3781da43cdb8f8d204a Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Wed, 3 Nov 2010 21:24:05 +0100 Subject: [PATCH 106/207] Limited max window transparency to 250 (i.e. min alpha is 5) --- Console/DlgSettingsStyles.cpp | 4 ++-- Console/SettingsHandler.cpp | 5 +++++ Console/SettingsHandler.h | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Console/DlgSettingsStyles.cpp b/Console/DlgSettingsStyles.cpp index 654e7ca3..c58bd0de 100644 --- a/Console/DlgSettingsStyles.cpp +++ b/Console/DlgSettingsStyles.cpp @@ -58,12 +58,12 @@ LRESULT DlgSettingsStyles::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM spin.Detach(); m_sliderActiveAlpha.Attach(GetDlgItem(IDC_ACTIVE_ALPHA)); - m_sliderActiveAlpha.SetRange(0, 255); + m_sliderActiveAlpha.SetRange(0, 255 - TransparencySettings::minAlpha); m_sliderActiveAlpha.SetTicFreq(5); m_sliderActiveAlpha.SetPageSize(5); m_sliderInactiveAlpha.Attach(GetDlgItem(IDC_INACTIVE_ALPHA)); - m_sliderInactiveAlpha.SetRange(0, 255); + m_sliderInactiveAlpha.SetRange(0, 255 - TransparencySettings::minAlpha); m_sliderInactiveAlpha.SetTicFreq(5); m_sliderInactiveAlpha.SetPageSize(5); diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index 1b725685..9a659a71 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -625,6 +625,8 @@ PositionSettings& PositionSettings::operator=(const PositionSettings& other) ////////////////////////////////////////////////////////////////////////////// +BYTE TransparencySettings::minAlpha = 5; + ////////////////////////////////////////////////////////////////////////////// TransparencySettings::TransparencySettings() @@ -651,6 +653,9 @@ bool TransparencySettings::Load(const CComPtr& pSettingsRoot) XmlHelper::GetAttribute(pTransElement, CComBSTR(L"inactive_alpha"), byInactiveAlpha, 255); XmlHelper::GetRGBAttribute(pTransElement, crColorKey, RGB(0, 0, 0)); + if (byActiveAlpha < minAlpha) byActiveAlpha = minAlpha; + if (byInactiveAlpha < minAlpha) byInactiveAlpha = minAlpha; + return true; } diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index e3422799..072fccc6 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -246,6 +246,8 @@ struct TransparencySettings : public SettingsBase BYTE byActiveAlpha; BYTE byInactiveAlpha; COLORREF crColorKey; + + static BYTE minAlpha; }; ////////////////////////////////////////////////////////////////////////////// From 13d51831b185d0e714f23f1496c30e689ca446d9 Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Wed, 3 Nov 2010 22:17:48 +0100 Subject: [PATCH 107/207] Added checks for console row/column/buffer numbers. --- Console/Console.rc | 14 +++++++++- Console/DlgSettingsAppearance.cpp | 1 - Console/DlgSettingsBase.h | 7 +++++ Console/DlgSettingsBehavior.cpp | 1 - Console/DlgSettingsConsole.cpp | 46 +++++++++++++++++++++++++++++-- Console/DlgSettingsConsole.h | 10 ++++--- Console/DlgSettingsHotkeys.cpp | 1 - Console/DlgSettingsMain.cpp | 11 +++++++- Console/DlgSettingsMouse.cpp | 1 - Console/DlgSettingsStyles.cpp | 1 - Console/DlgSettingsTabs.cpp | 1 - Console/resource.h | 4 +++ 12 files changed, 84 insertions(+), 14 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index f5705190..1b6df638 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -982,6 +982,18 @@ BEGIN ID_UNGROUP_TAB "Remove grouping of all terminals in the current tab\nUngroup Tab" END +STRINGTABLE +BEGIN + MSG_SETTINGS_INVALID_BUFFER_ROWS + "Invalid number of console buffer rows! Must be between 0 and 9999." + MSG_SETTINGS_INVALID_BUFFER_COLUMNS + "Invalid number of console buffer columns! Must be between 0 and 200." + MSG_SETTINGS_INVALID_ROWS + "Invalid number of console rows! Must be between 0 and 200." + MSG_SETTINGS_INVALID_COLUMNS + "Invalid number of console columns! Must be between 0 and 200." +END + #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// @@ -992,7 +1004,7 @@ END // // Generated from the TEXTINCLUDE 3 resource. // - + ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED diff --git a/Console/DlgSettingsAppearance.cpp b/Console/DlgSettingsAppearance.cpp index 975413c1..01b75cea 100644 --- a/Console/DlgSettingsAppearance.cpp +++ b/Console/DlgSettingsAppearance.cpp @@ -196,7 +196,6 @@ LRESULT DlgSettingsAppearance::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND / m_positionSettings.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } diff --git a/Console/DlgSettingsBase.h b/Console/DlgSettingsBase.h index d3e680cf..2eaef791 100644 --- a/Console/DlgSettingsBase.h +++ b/Console/DlgSettingsBase.h @@ -27,6 +27,13 @@ class DlgSettingsBase { } + public: + + virtual void OnDataValidateError(UINT nCtrlID, BOOL bSave, _XData& data) + { + CWinDataExchange::OnDataValidateError(nCtrlID, bSave, data); + } + protected: CComPtr& m_pOptionsRoot; diff --git a/Console/DlgSettingsBehavior.cpp b/Console/DlgSettingsBehavior.cpp index 6a5ec926..8c037fcd 100644 --- a/Console/DlgSettingsBehavior.cpp +++ b/Console/DlgSettingsBehavior.cpp @@ -97,7 +97,6 @@ LRESULT DlgSettingsBehavior::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*h m_behaviorSettings.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } diff --git a/Console/DlgSettingsConsole.cpp b/Console/DlgSettingsConsole.cpp index 609cef54..4e4e8b7d 100644 --- a/Console/DlgSettingsConsole.cpp +++ b/Console/DlgSettingsConsole.cpp @@ -136,7 +136,8 @@ LRESULT DlgSettingsConsole::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hW { if (wID == IDOK) { - DoDataExchange(DDX_SAVE); + if (!DoDataExchange(DDX_SAVE)) return -1; + m_consoleSettings.strShell = m_strShell; m_consoleSettings.strInitialDir = m_strInitialDir; @@ -150,7 +151,6 @@ LRESULT DlgSettingsConsole::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hW m_consoleSettings.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } @@ -230,3 +230,45 @@ LRESULT DlgSettingsConsole::OnClickedClrBtn(WORD /*wNotifyCode*/, WORD wID, HWND ////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// + +void DlgSettingsConsole::OnDataValidateError(UINT nCtrlID, BOOL bSave, _XData& data) +{ + CString message; + + switch (nCtrlID) + { + case IDC_BUFFER_ROWS : + { + message.LoadString(MSG_SETTINGS_INVALID_BUFFER_ROWS); + break; + } + + case IDC_BUFFER_COLUMNS : + { + message.LoadString(MSG_SETTINGS_INVALID_BUFFER_COLUMNS); + break; + } + + case IDC_ROWS : + { + message.LoadString(MSG_SETTINGS_INVALID_ROWS); + break; + } + + case IDC_COLUMNS : + { + message.LoadString(MSG_SETTINGS_INVALID_COLUMNS); + break; + } + + default: break; + } + + if (message.GetLength() > 0) ::MessageBox(this->GetParent(), message, L"Error", MB_OK|MB_ICONERROR); + + DlgSettingsBase::OnDataValidateError(nCtrlID, bSave, data); +} + +////////////////////////////////////////////////////////////////////////////// diff --git a/Console/DlgSettingsConsole.h b/Console/DlgSettingsConsole.h index 39d245b2..e3f975da 100644 --- a/Console/DlgSettingsConsole.h +++ b/Console/DlgSettingsConsole.h @@ -26,11 +26,11 @@ class DlgSettingsConsole DDX_CHECK(IDC_CHECK_START_HIDDEN, m_nStartHidden) DDX_UINT(IDC_CHANGE_REFRESH, m_consoleSettings.dwChangeRefreshInterval) DDX_UINT(IDC_REFRESH, m_consoleSettings.dwRefreshInterval) - DDX_UINT(IDC_ROWS, m_consoleSettings.dwRows) - DDX_UINT(IDC_COLUMNS, m_consoleSettings.dwColumns) + DDX_UINT_RANGE(IDC_ROWS, m_consoleSettings.dwRows, static_cast(10), static_cast(200)) + DDX_UINT_RANGE(IDC_COLUMNS, m_consoleSettings.dwColumns, static_cast(10), static_cast(200)) DDX_CHECK(IDC_CHECK_SAVE_SIZE, m_nSaveSize) - DDX_UINT(IDC_BUFFER_ROWS, m_consoleSettings.dwBufferRows) - DDX_UINT(IDC_BUFFER_COLUMNS, m_consoleSettings.dwBufferColumns) + DDX_UINT_RANGE(IDC_BUFFER_ROWS, m_consoleSettings.dwBufferRows, static_cast(0), static_cast(9999)) + DDX_UINT_RANGE(IDC_BUFFER_COLUMNS, m_consoleSettings.dwBufferColumns, static_cast(0), static_cast(200)) END_DDX_MAP() BEGIN_MSG_MAP(DlgSettingsConsole) @@ -59,6 +59,8 @@ class DlgSettingsConsole LRESULT OnClickedBtnResetColors(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); LRESULT OnClickedClrBtn(WORD /*wNotifyCode*/, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/); + virtual void OnDataValidateError(UINT nCtrlID, BOOL bSave, _XData& data); + private: ConsoleSettings m_consoleSettings; diff --git a/Console/DlgSettingsHotkeys.cpp b/Console/DlgSettingsHotkeys.cpp index 9af479ac..785c1c66 100644 --- a/Console/DlgSettingsHotkeys.cpp +++ b/Console/DlgSettingsHotkeys.cpp @@ -170,7 +170,6 @@ LRESULT DlgSettingsHotkeys::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hW hotKeys.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } diff --git a/Console/DlgSettingsMain.cpp b/Console/DlgSettingsMain.cpp index ac00e47b..8b0d8ea5 100644 --- a/Console/DlgSettingsMain.cpp +++ b/Console/DlgSettingsMain.cpp @@ -73,7 +73,16 @@ LRESULT DlgSettingsMain::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndC SettingsDlgsMap::iterator it = m_settingsDlgMap.begin(); for (; it != m_settingsDlgMap.end(); ++it) { - (it->second)->SendMessage(WM_COMMAND, wID, 0); + if ((it->second)->SendMessage(WM_COMMAND, wID, 0) != 0) + { + m_treeCtrl.Select(it->first, TVGN_CARET); + return -1; + } + } + + for (it = m_settingsDlgMap.begin(); it != m_settingsDlgMap.end(); ++it) + { + it->second->DestroyWindow(); } if (wID == IDOK) diff --git a/Console/DlgSettingsMouse.cpp b/Console/DlgSettingsMouse.cpp index 6ee045b7..bd72703c 100644 --- a/Console/DlgSettingsMouse.cpp +++ b/Console/DlgSettingsMouse.cpp @@ -166,7 +166,6 @@ LRESULT DlgSettingsMouse::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWnd mouseSettings.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } diff --git a/Console/DlgSettingsStyles.cpp b/Console/DlgSettingsStyles.cpp index c58bd0de..c99f021d 100644 --- a/Console/DlgSettingsStyles.cpp +++ b/Console/DlgSettingsStyles.cpp @@ -170,7 +170,6 @@ LRESULT DlgSettingsStyles::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWn m_transparencySettings.Save(m_pOptionsRoot); } - DestroyWindow(); return 0; } diff --git a/Console/DlgSettingsTabs.cpp b/Console/DlgSettingsTabs.cpp index 4f0c0b73..716b4c89 100644 --- a/Console/DlgSettingsTabs.cpp +++ b/Console/DlgSettingsTabs.cpp @@ -131,7 +131,6 @@ LRESULT DlgSettingsTabs::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndC m_tabSettings.tabDataVector.end()); } - DestroyWindow(); return 0; } diff --git a/Console/resource.h b/Console/resource.h index 1651b917..042dd99f 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -247,6 +247,10 @@ #define IDS_ERR_CANT_START_SHELL 5000 #define IDS_ERR_CANT_START_AS_USER 5001 #define IDS_ERR_CANT_START_SHELL_AS_USER 5001 +#define MSG_SETTINGS_INVALID_BUFFER_ROWS 10000 +#define MSG_SETTINGS_INVALID_BUFFER_COLUMNS 10001 +#define MSG_SETTINGS_INVALID_ROWS 10002 +#define MSG_SETTINGS_INVALID_COLUMNS 10003 #define ID_FILE_NEW_TAB 32775 #define ID_VIEW_CONSOLE 32777 #define ID_FILE_CLOSE_TAB 32779 From 580e793bdab7d2f544e42e533457ae4757765b8f Mon Sep 17 00:00:00 2001 From: Marko Bozikovic Date: Wed, 3 Nov 2010 23:23:09 +0100 Subject: [PATCH 108/207] Cleaned up settings dialogs' code a bit --- Console/DlgSettingsAppearance.cpp | 59 ++++++++++--------------------- Console/DlgSettingsAppearance.h | 39 ++++++++------------ Console/DlgSettingsBehavior.cpp | 22 +++--------- Console/DlgSettingsBehavior.h | 21 ++++------- Console/DlgSettingsConsole.cpp | 8 ----- Console/DlgSettingsConsole.h | 7 ++-- Console/DlgSettingsHotkeys.cpp | 13 ------- Console/DlgSettingsHotkeys.h | 4 +-- Console/DlgSettingsStyles.cpp | 32 +---------------- Console/DlgSettingsStyles.h | 41 +++++++-------------- Console/PageSettingsTabs1.cpp | 8 ++--- Console/PageSettingsTabs1.h | 4 +-- Console/PageSettingsTabs2.cpp | 20 ++++------- Console/PageSettingsTabs2.h | 8 ++--- 14 files changed, 80 insertions(+), 206 deletions(-) diff --git a/Console/DlgSettingsAppearance.cpp b/Console/DlgSettingsAppearance.cpp index 01b75cea..3bad8028 100644 --- a/Console/DlgSettingsAppearance.cpp +++ b/Console/DlgSettingsAppearance.cpp @@ -42,29 +42,19 @@ LRESULT DlgSettingsAppearance::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LP m_positionSettings.Load(m_pOptionsRoot); m_strWindowTitle = m_windowSettings.strTitle.c_str(); - m_nUseTabTitle = m_windowSettings.bUseTabTitles ? 1 : 0; - m_nUseConsoleTitle = m_windowSettings.bUseConsoleTitle ? 1 : 0; - m_nShowCommand = m_windowSettings.bShowCommand ? 1 : 0; - m_nShowCommandTabs = m_windowSettings.bShowCommandInTabs ? 1 : 0; - m_nTrimTabTitles = (m_windowSettings.dwTrimTabTitles > 0) ? 1 : 0; + m_bTrimTabTitles = (m_windowSettings.dwTrimTabTitles > 0); m_strWindowIcon = m_windowSettings.strIcon.c_str(); - m_nUseTabIcon = m_windowSettings.bUseTabIcon ? 1 : 0; m_strFontName = m_fontSettings.strName.c_str(); - m_nFontBold = m_fontSettings.bBold ? 1 : 0; - m_nFontItalic = m_fontSettings.bItalic ? 1 : 0; m_comboFontSmoothing.SetCurSel(static_cast(m_fontSettings.fontSmoothing)); - m_nUseFontColor = m_fontSettings.bUseColor ? 1 : 0; - - m_nUsePosition = ((m_positionSettings.nX == -1) && (m_positionSettings.nY == -1)) ? 0 : 1; + m_bUsePosition = ((m_positionSettings.nX == -1) && (m_positionSettings.nY == -1)) ? 0 : 1; m_nX = ((m_positionSettings.nX == -1) && (m_positionSettings.nY == -1)) ? 0 : m_positionSettings.nX; m_nY = ((m_positionSettings.nX == -1) && (m_positionSettings.nY == -1)) ? 0 : m_positionSettings.nY; - m_nSavePosition = m_positionSettings.bSavePosition ? 1 : 0; - m_nSnapToEdges = (m_positionSettings.nSnapDistance == -1) ? 0 : 1; - if (m_nSnapToEdges == 0) m_positionSettings.nSnapDistance = 0; + m_bSnapToEdges = (m_positionSettings.nSnapDistance != -1); + if (!m_bSnapToEdges) m_positionSettings.nSnapDistance = 0; m_comboDocking.SetCurSel(static_cast(m_positionSettings.dockPosition) + 1); m_comboZOrder.SetCurSel(static_cast(m_positionSettings.zOrder)); @@ -140,25 +130,16 @@ LRESULT DlgSettingsAppearance::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND / DoDataExchange(DDX_SAVE); m_windowSettings.strTitle = m_strWindowTitle; - m_windowSettings.bUseTabTitles = (m_nUseTabTitle > 0); - m_windowSettings.bUseConsoleTitle = (m_nUseConsoleTitle > 0); - m_windowSettings.bShowCommand = (m_nShowCommand > 0); - m_windowSettings.bShowCommandInTabs = (m_nShowCommandTabs > 0); - if (m_nTrimTabTitles == 0) m_windowSettings.dwTrimTabTitles = 0; + if (!m_bTrimTabTitles) m_windowSettings.dwTrimTabTitles = 0; m_windowSettings.strIcon = m_strWindowIcon; - m_windowSettings.bUseTabIcon = (m_nUseTabIcon > 0); if (m_fontSettings.dwSize > 36) m_fontSettings.dwSize = 36; m_fontSettings.strName = m_strFontName; - m_fontSettings.bBold = (m_nFontBold > 0); - m_fontSettings.bItalic = (m_nFontItalic > 0); m_fontSettings.fontSmoothing = static_cast(m_comboFontSmoothing.GetCurSel()); - m_fontSettings.bUseColor = (m_nUseFontColor > 0); - - if (m_nUsePosition > 0) + if (m_bUsePosition) { m_positionSettings.nX = m_nX; m_positionSettings.nY = m_nY; @@ -173,9 +154,7 @@ LRESULT DlgSettingsAppearance::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND / m_positionSettings.nY = -1; } - m_positionSettings.bSavePosition = (m_nSavePosition > 0); - - if (m_nSnapToEdges == 0) + if (!m_bSnapToEdges) { m_positionSettings.nSnapDistance = -1; } @@ -238,18 +217,18 @@ LRESULT DlgSettingsAppearance::OnClickedBtnBrowseFont(WORD /*wNotifyCode*/, WORD wcsncpy_s(lf.lfFaceName, _countof(lf.lfFaceName), LPCTSTR(m_strFontName), 32); lf.lfHeight = -MulDiv(m_fontSettings.dwSize, GetDeviceCaps(::GetDC(NULL), LOGPIXELSY), 72); - lf.lfWeight = (m_nFontBold > 0) ? FW_BOLD : FW_NORMAL; - lf.lfItalic = static_cast(m_nFontItalic); + lf.lfWeight = m_fontSettings.bBold ? FW_BOLD : FW_NORMAL; + lf.lfItalic = m_fontSettings.bItalic ? 1 : 0; CFontDialog fontDlg(&lf, CF_FIXEDPITCHONLY|CF_SCREENFONTS); if (fontDlg.DoModal() == IDOK) { - m_strFontName = fontDlg.GetFaceName();// fontDlg.m_lf.lfFaceName; + m_strFontName = fontDlg.GetFaceName(); m_fontSettings.dwSize= static_cast(static_cast(-fontDlg.m_lf.lfHeight*72)/static_cast(GetDeviceCaps(::GetDC(NULL), LOGPIXELSY)) + 0.5); - m_nFontBold = fontDlg.IsBold() ? 1 : 0; //(fontDlg.m_lf.lfWeight == FW_BOLD) ? 1 : 0; - m_nFontItalic = fontDlg.IsItalic() ? 1 : 0; // fontDlg.m_lf.lfItalic; + m_fontSettings.bBold = fontDlg.IsBold() ? true : false; + m_fontSettings.bItalic = fontDlg.IsItalic() ? true : false; DoDataExchange(DDX_LOAD); } @@ -319,15 +298,15 @@ void DlgSettingsAppearance::EnableControls() GetDlgItem(IDC_SNAP).EnableWindow(FALSE); GetDlgItem(IDC_SPIN_SNAP).EnableWindow(FALSE); - if (m_nUseTabTitle == 0) GetDlgItem(IDC_WINDOW_TITLE).EnableWindow(); + if (!m_windowSettings.bUseTabTitles) GetDlgItem(IDC_WINDOW_TITLE).EnableWindow(); - if (m_nUseConsoleTitle == 0) + if (!m_windowSettings.bUseConsoleTitle) { GetDlgItem(IDC_CHECK_SHOW_COMMAND).EnableWindow(); GetDlgItem(IDC_CHECK_SHOW_COMMAND_TABS).EnableWindow(); } - if (m_nTrimTabTitles > 0) + if (m_bTrimTabTitles) { GetDlgItem(IDC_TRIM_TAB_TITLES).EnableWindow(); GetDlgItem(IDC_SPIN_TRIM_TAB_TITLES).EnableWindow(); @@ -337,18 +316,18 @@ void DlgSettingsAppearance::EnableControls() GetDlgItem(IDC_STATIC_TRIM_CHARS_RIGHT).EnableWindow(); } - if (m_nUseTabIcon == 0) + if (!m_windowSettings.bUseTabIcon) { GetDlgItem(IDC_WINDOW_ICON).EnableWindow(); GetDlgItem(IDC_BTN_BROWSE_ICON).EnableWindow(); } - if (m_nUseFontColor > 0) + if (m_fontSettings.bUseColor) { GetDlgItem(IDC_FONT_COLOR).EnableWindow(); } - if (m_nUsePosition > 0) + if (m_bUsePosition) { GetDlgItem(IDC_POS_X).EnableWindow(); GetDlgItem(IDC_POS_Y).EnableWindow(); @@ -356,7 +335,7 @@ void DlgSettingsAppearance::EnableControls() GetDlgItem(IDC_SPIN_Y).EnableWindow(); } - if (m_nSnapToEdges > 0) + if (m_bSnapToEdges) { GetDlgItem(IDC_SNAP).EnableWindow(); GetDlgItem(IDC_SPIN_SNAP).EnableWindow(); diff --git a/Console/DlgSettingsAppearance.h b/Console/DlgSettingsAppearance.h index 31f9873c..2559366d 100644 --- a/Console/DlgSettingsAppearance.h +++ b/Console/DlgSettingsAppearance.h @@ -22,25 +22,25 @@ class DlgSettingsAppearance BEGIN_DDX_MAP(DlgSettingsAppearance) DDX_TEXT(IDC_WINDOW_TITLE, m_strWindowTitle) - DDX_CHECK(IDC_CHECK_USE_TAB_TITLE, m_nUseTabTitle) - DDX_CHECK(IDC_CHECK_USE_CONSOLE_TITLE, m_nUseConsoleTitle) - DDX_CHECK(IDC_CHECK_SHOW_COMMAND, m_nShowCommand) - DDX_CHECK(IDC_CHECK_SHOW_COMMAND_TABS, m_nShowCommandTabs) - DDX_CHECK(IDC_CHECK_TRIM_TAB_TITLES, m_nTrimTabTitles) + DDX_CHECK(IDC_CHECK_USE_TAB_TITLE, m_windowSettings.bUseTabTitles) + DDX_CHECK(IDC_CHECK_USE_CONSOLE_TITLE, m_windowSettings.bUseConsoleTitle) + DDX_CHECK(IDC_CHECK_SHOW_COMMAND, m_windowSettings.bShowCommand) + DDX_CHECK(IDC_CHECK_SHOW_COMMAND_TABS, m_windowSettings.bShowCommandInTabs) + DDX_CHECK(IDC_CHECK_TRIM_TAB_TITLES, m_bTrimTabTitles) DDX_UINT(IDC_TRIM_TAB_TITLES, m_windowSettings.dwTrimTabTitles) DDX_UINT(IDC_TRIM_TAB_TITLES_RIGHT, m_windowSettings.dwTrimTabTitlesRight) DDX_TEXT(IDC_WINDOW_ICON, m_strWindowIcon) - DDX_CHECK(IDC_CHECK_USE_TAB_ICON, m_nUseTabIcon) + DDX_CHECK(IDC_CHECK_USE_TAB_ICON, m_windowSettings.bUseTabIcon) DDX_TEXT(IDC_FONT, m_strFontName) DDX_UINT(IDC_FONT_SIZE, m_fontSettings.dwSize) - DDX_CHECK(IDC_CHECK_BOLD, m_nFontBold) - DDX_CHECK(IDC_CHECK_ITALIC, m_nFontItalic) - DDX_CHECK(IDC_CHECK_USE_COLOR, m_nUseFontColor) - DDX_CHECK(IDC_CHECK_POSITION, m_nUsePosition) + DDX_CHECK(IDC_CHECK_BOLD, m_fontSettings.bBold) + DDX_CHECK(IDC_CHECK_ITALIC, m_fontSettings.bItalic) + DDX_CHECK(IDC_CHECK_USE_COLOR, m_fontSettings.bUseColor) + DDX_CHECK(IDC_CHECK_POSITION, m_bUsePosition) DDX_INT(IDC_POS_X, m_nX) DDX_INT(IDC_POS_Y, m_nY) - DDX_CHECK(IDC_CHECK_SAVE_POSITION, m_nSavePosition) - DDX_CHECK(IDC_CHECK_SNAP, m_nSnapToEdges) + DDX_CHECK(IDC_CHECK_SAVE_POSITION, m_positionSettings.bSavePosition) + DDX_CHECK(IDC_CHECK_SNAP, m_bSnapToEdges) DDX_INT(IDC_SNAP, m_positionSettings.nSnapDistance) END_DDX_MAP() @@ -87,24 +87,15 @@ class DlgSettingsAppearance PositionSettings m_positionSettings; CString m_strWindowTitle; - int m_nUseTabTitle; - int m_nUseConsoleTitle; - int m_nShowCommand; - int m_nShowCommandTabs; - int m_nTrimTabTitles; + bool m_bTrimTabTitles; CString m_strWindowIcon; - int m_nUseTabIcon; CString m_strFontName; - int m_nFontBold; - int m_nFontItalic; - int m_nUseFontColor; - int m_nUsePosition; + bool m_bUsePosition; int m_nX; int m_nY; - int m_nSavePosition; - int m_nSnapToEdges; + bool m_bSnapToEdges; CComboBox m_comboFontSmoothing; CComboBox m_comboDocking; diff --git a/Console/DlgSettingsBehavior.cpp b/Console/DlgSettingsBehavior.cpp index 8c037fcd..e9513b62 100644 --- a/Console/DlgSettingsBehavior.cpp +++ b/Console/DlgSettingsBehavior.cpp @@ -33,16 +33,9 @@ LRESULT DlgSettingsBehavior::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPAR { m_behaviorSettings.Load(m_pOptionsRoot); - m_nCopyOnSelect = m_behaviorSettings.copyPasteSettings.bCopyOnSelect ? 1 : 0; - m_nClearOnCopy = m_behaviorSettings.copyPasteSettings.bClearOnCopy ? 1 : 0; - m_nNoWrap = m_behaviorSettings.copyPasteSettings.bNoWrap ? 1 : 0; - m_nTrimSpaces = m_behaviorSettings.copyPasteSettings.bTrimSpaces ? 1 : 0; - m_nCopyNewlineChar= static_cast(m_behaviorSettings.copyPasteSettings.copyNewlineChar); - - m_nScrollPageType= m_behaviorSettings.scrollSettings.dwPageScrollRows ? 1 : 0; - - m_nFlashInactiveTab= m_behaviorSettings.tabHighlightSettings.dwFlashes > 0 ? 1 : 0; - m_nLeaveHighlighted= m_behaviorSettings.tabHighlightSettings.bStayHighlighted ? 1 : 0; + m_nCopyNewlineChar = static_cast(m_behaviorSettings.copyPasteSettings.copyNewlineChar); + m_nScrollPageType = m_behaviorSettings.scrollSettings.dwPageScrollRows ? 1 : 0; + m_bFlashInactiveTab = (m_behaviorSettings.tabHighlightSettings.dwFlashes > 0); CUpDownCtrl spin; UDACCEL udAccel; @@ -80,16 +73,11 @@ LRESULT DlgSettingsBehavior::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*h { DoDataExchange(DDX_SAVE); - m_behaviorSettings.copyPasteSettings.bCopyOnSelect = (m_nCopyOnSelect > 0); - m_behaviorSettings.copyPasteSettings.bClearOnCopy = (m_nClearOnCopy > 0); - m_behaviorSettings.copyPasteSettings.bNoWrap = (m_nNoWrap > 0); - m_behaviorSettings.copyPasteSettings.bTrimSpaces = (m_nTrimSpaces > 0); m_behaviorSettings.copyPasteSettings.copyNewlineChar= static_cast(m_nCopyNewlineChar); if (m_nScrollPageType == 0) m_behaviorSettings.scrollSettings.dwPageScrollRows = 0; - if (m_nFlashInactiveTab == 0) m_behaviorSettings.tabHighlightSettings.dwFlashes = 0; - m_behaviorSettings.tabHighlightSettings.bStayHighlighted = (m_nLeaveHighlighted > 0); + if (!m_bFlashInactiveTab) m_behaviorSettings.tabHighlightSettings.dwFlashes = 0; BehaviorSettings& behaviorSettings = g_settingsHandler->GetBehaviorSettings(); @@ -165,7 +153,7 @@ void DlgSettingsBehavior::EnableFlashTabControls() GetDlgItem(IDC_SPIN_TAB_FLASHES).EnableWindow(FALSE); GetDlgItem(IDC_CHECK_LEAVE_HIGHLIGHTED).EnableWindow(FALSE); - if (m_nFlashInactiveTab > 0) + if (m_bFlashInactiveTab) { if (m_behaviorSettings.tabHighlightSettings.dwFlashes == 0) { diff --git a/Console/DlgSettingsBehavior.h b/Console/DlgSettingsBehavior.h index e286d671..8adaacf8 100644 --- a/Console/DlgSettingsBehavior.h +++ b/Console/DlgSettingsBehavior.h @@ -21,16 +21,16 @@ class DlgSettingsBehavior DlgSettingsBehavior(CComPtr& pOptionsRoot); BEGIN_DDX_MAP(DlgSettingsBehavior) - DDX_CHECK(IDC_CHECK_COPY_ON_SELECT, m_nCopyOnSelect) - DDX_CHECK(IDC_CHECK_CLEAR_ON_COPY, m_nClearOnCopy) - DDX_CHECK(IDC_CHECK_NO_WRAP, m_nNoWrap) - DDX_CHECK(IDC_CHECK_TRIM_SPACES, m_nTrimSpaces) + DDX_CHECK(IDC_CHECK_COPY_ON_SELECT, m_behaviorSettings.copyPasteSettings.bCopyOnSelect) + DDX_CHECK(IDC_CHECK_CLEAR_ON_COPY, m_behaviorSettings.copyPasteSettings.bClearOnCopy) + DDX_CHECK(IDC_CHECK_NO_WRAP, m_behaviorSettings.copyPasteSettings.bNoWrap) + DDX_CHECK(IDC_CHECK_TRIM_SPACES, m_behaviorSettings.copyPasteSettings.bTrimSpaces) DDX_RADIO(IDC_RADIO_COPY_NEWLINE_CHAR, m_nCopyNewlineChar) DDX_RADIO(IDC_PAGE_SCROLL, m_nScrollPageType) DDX_UINT(IDC_SCROLL_PAGE_ROWS, m_behaviorSettings.scrollSettings.dwPageScrollRows) - DDX_CHECK(IDC_CHECK_FLASH_TAB, m_nFlashInactiveTab) + DDX_CHECK(IDC_CHECK_FLASH_TAB, m_bFlashInactiveTab) DDX_UINT(IDC_TAB_FLASHES, m_behaviorSettings.tabHighlightSettings.dwFlashes) - DDX_CHECK(IDC_CHECK_LEAVE_HIGHLIGHTED, m_nLeaveHighlighted) + DDX_CHECK(IDC_CHECK_LEAVE_HIGHLIGHTED, m_behaviorSettings.tabHighlightSettings.bStayHighlighted) END_DDX_MAP() BEGIN_MSG_MAP(DlgSettingsBehavior) @@ -62,18 +62,11 @@ class DlgSettingsBehavior BehaviorSettings m_behaviorSettings; - int m_nCopyOnSelect; - int m_nClearOnCopy; - int m_nNoWrap; - int m_nTrimSpaces; - int m_nCopyNewlineChar; int m_nScrollPageType; - int m_nFlashInactiveTab; - int m_nLeaveHighlighted; - + bool m_bFlashInactiveTab; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/DlgSettingsConsole.cpp b/Console/DlgSettingsConsole.cpp index 4e4e8b7d..fb974ef0 100644 --- a/Console/DlgSettingsConsole.cpp +++ b/Console/DlgSettingsConsole.cpp @@ -18,8 +18,6 @@ DlgSettingsConsole::DlgSettingsConsole(CComPtr& pOptionsRoot) : DlgSettingsBase(pOptionsRoot) , m_strShell(L"") , m_strInitialDir(L"") -, m_nStartHidden(0) -, m_nSaveSize(0) { IDD = IDD_SETTINGS_CONSOLE; } @@ -40,9 +38,6 @@ LRESULT DlgSettingsConsole::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARA m_strShell = m_consoleSettings.strShell.c_str(); m_strInitialDir = m_consoleSettings.strInitialDir.c_str(); - m_nStartHidden = m_consoleSettings.bStartHidden ? 1 : 0; - m_nSaveSize = m_consoleSettings.bSaveSize ? 1 : 0; - CUpDownCtrl spin; UDACCEL udAccel; @@ -141,9 +136,6 @@ LRESULT DlgSettingsConsole::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hW m_consoleSettings.strShell = m_strShell; m_consoleSettings.strInitialDir = m_strInitialDir; - m_consoleSettings.bStartHidden = (m_nStartHidden > 0); - m_consoleSettings.bSaveSize = (m_nSaveSize > 0); - // set immediate settings ConsoleSettings& consoleSettings = g_settingsHandler->GetConsoleSettings(); diff --git a/Console/DlgSettingsConsole.h b/Console/DlgSettingsConsole.h index e3f975da..03836ee0 100644 --- a/Console/DlgSettingsConsole.h +++ b/Console/DlgSettingsConsole.h @@ -23,12 +23,12 @@ class DlgSettingsConsole BEGIN_DDX_MAP(DlgSettingsConsole) DDX_TEXT(IDC_SHELL, m_strShell) DDX_TEXT(IDC_INIT_DIR, m_strInitialDir) - DDX_CHECK(IDC_CHECK_START_HIDDEN, m_nStartHidden) + DDX_CHECK(IDC_CHECK_START_HIDDEN, m_consoleSettings.bStartHidden) DDX_UINT(IDC_CHANGE_REFRESH, m_consoleSettings.dwChangeRefreshInterval) DDX_UINT(IDC_REFRESH, m_consoleSettings.dwRefreshInterval) DDX_UINT_RANGE(IDC_ROWS, m_consoleSettings.dwRows, static_cast(10), static_cast(200)) DDX_UINT_RANGE(IDC_COLUMNS, m_consoleSettings.dwColumns, static_cast(10), static_cast(200)) - DDX_CHECK(IDC_CHECK_SAVE_SIZE, m_nSaveSize) + DDX_CHECK(IDC_CHECK_SAVE_SIZE, m_consoleSettings.bSaveSize) DDX_UINT_RANGE(IDC_BUFFER_ROWS, m_consoleSettings.dwBufferRows, static_cast(0), static_cast(9999)) DDX_UINT_RANGE(IDC_BUFFER_COLUMNS, m_consoleSettings.dwBufferColumns, static_cast(0), static_cast(200)) END_DDX_MAP() @@ -67,9 +67,6 @@ class DlgSettingsConsole CString m_strShell; CString m_strInitialDir; - - int m_nStartHidden; - int m_nSaveSize; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/DlgSettingsHotkeys.cpp b/Console/DlgSettingsHotkeys.cpp index 785c1c66..4366fbd7 100644 --- a/Console/DlgSettingsHotkeys.cpp +++ b/Console/DlgSettingsHotkeys.cpp @@ -15,7 +15,6 @@ DlgSettingsHotkeys::DlgSettingsHotkeys(CComPtr& pOptionsRoot) : DlgSettingsBase(pOptionsRoot) -, m_nUseScrollLock(0) { IDD = IDD_SETTINGS_HOTKEYS; } @@ -34,8 +33,6 @@ LRESULT DlgSettingsHotkeys::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARA { m_hotKeys.Load(m_pOptionsRoot); - m_nUseScrollLock = m_hotKeys.bUseScrollLock ? 1 : 0; - m_listCtrl.Attach(GetDlgItem(IDC_LIST_HOTKEYS)); m_editCommand.Attach(GetDlgItem(IDC_EDIT_COMMAND)); m_hotKeyEdit.SubclassWindow(GetDlgItem(IDC_EDIT_HOTKEY)); @@ -156,17 +153,7 @@ LRESULT DlgSettingsHotkeys::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hW HotKeys& hotKeys = g_settingsHandler->GetHotKeys(); - m_hotKeys.bUseScrollLock = (m_nUseScrollLock > 0); - hotKeys = m_hotKeys; - -/* - hotKeys.bUseScrollLock = m_hotKeys.bUseScrollLock; - - hotKeys.commands.clear(); - hotKeys.commands.insert(hotKeys.commands.begin(), m_hotKeys.commands.begin(), m_hotKeys.commands.end()); -*/ - hotKeys.Save(m_pOptionsRoot); } diff --git a/Console/DlgSettingsHotkeys.h b/Console/DlgSettingsHotkeys.h index 0a5fe391..a8bcdfd4 100644 --- a/Console/DlgSettingsHotkeys.h +++ b/Console/DlgSettingsHotkeys.h @@ -22,7 +22,7 @@ class DlgSettingsHotkeys DlgSettingsHotkeys(CComPtr& pOptionsRoot); BEGIN_DDX_MAP(DlgSettingsHotkeys) - DDX_CHECK(IDC_CHECK_USE_SCROLL_LOCK, m_nUseScrollLock) + DDX_CHECK(IDC_CHECK_USE_SCROLL_LOCK, m_hotKeys.bUseScrollLock) END_DDX_MAP() BEGIN_MSG_MAP(DlgSettingsHotkeys) @@ -54,8 +54,6 @@ class DlgSettingsHotkeys CListViewCtrl m_listCtrl; CEdit m_editCommand; CHotkeyEdit m_hotKeyEdit; - - int m_nUseScrollLock; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/DlgSettingsStyles.cpp b/Console/DlgSettingsStyles.cpp index c99f021d..f91d0091 100644 --- a/Console/DlgSettingsStyles.cpp +++ b/Console/DlgSettingsStyles.cpp @@ -35,22 +35,7 @@ LRESULT DlgSettingsStyles::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM m_stylesSettings.Load(m_pOptionsRoot); m_transparencySettings.Load(m_pOptionsRoot); - m_nShowMenu = m_controlsSettings.bShowMenu ? 1 : 0; - m_nShowToolbar = m_controlsSettings.bShowToolbar ? 1 : 0; - m_nShowStatusbar= m_controlsSettings.bShowStatusbar ? 1 : 0; - m_nShowTabs = m_controlsSettings.bShowTabs ? 1 : 0; - m_nHideSingleTab= m_controlsSettings.bHideSingleTab ? 1 : 0; - m_nTabsOnBottom = m_controlsSettings.bTabsOnBottom ? 1 : 0; - m_nShowScrollbars= m_controlsSettings.bShowScrollbars ? 1 : 0; - m_nFlatScrollbars= m_controlsSettings.bFlatScrollbars ? 1 : 0; - - m_nShowCaption = m_stylesSettings.bCaption ? 1 : 0; - m_nResizable = m_stylesSettings.bResizable ? 1 : 0; - m_nTaskbarButton= m_stylesSettings.bTaskbarButton ? 1 : 0; - m_nBorder = m_stylesSettings.bBorder ? 1 : 0; - m_nTrayIcon = m_stylesSettings.bTrayIcon ? 1 : 0; m_nQuake = m_stylesSettings.bQuake ? 1 : 0; - CUpDownCtrl spin; spin.Attach(GetDlgItem(IDC_SPIN_INSIDE_BORDER)); @@ -138,22 +123,7 @@ LRESULT DlgSettingsStyles::OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWn if (m_stylesSettings.dwInsideBorder > 10) m_stylesSettings.dwInsideBorder = 10; - m_controlsSettings.bShowMenu = (m_nShowMenu > 0); - m_controlsSettings.bShowToolbar = (m_nShowToolbar > 0); - m_controlsSettings.bShowStatusbar = (m_nShowStatusbar > 0); - m_controlsSettings.bShowTabs = (m_nShowTabs > 0); - m_controlsSettings.bHideSingleTab = (m_nHideSingleTab > 0); - m_controlsSettings.bTabsOnBottom = (m_nTabsOnBottom > 0); - m_controlsSettings.bShowScrollbars = (m_nShowScrollbars > 0); - m_controlsSettings.bFlatScrollbars = (m_nFlatScrollbars > 0); - - m_stylesSettings.bCaption = (m_nShowCaption > 0); - m_stylesSettings.bResizable = (m_nResizable > 0); - m_stylesSettings.bTaskbarButton = (m_nTaskbarButton > 0); - m_stylesSettings.bBorder = (m_nBorder > 0); - m_stylesSettings.bTrayIcon = (m_nTrayIcon > 0); m_stylesSettings.bQuake = (m_nQuake > 0); - m_transparencySettings.byActiveAlpha = static_cast(255 - m_sliderActiveAlpha.GetPos()); m_transparencySettings.byInactiveAlpha = static_cast(255 - m_sliderInactiveAlpha.GetPos()); @@ -291,7 +261,7 @@ void DlgSettingsStyles::EnableTabControls() GetDlgItem(IDC_CHECK_HIDE_SINGLE_TAB).EnableWindow(FALSE); GetDlgItem(IDC_CHECK_TABS_ON_BOTTOM).EnableWindow(FALSE); - if (m_nShowTabs > 0) + if (m_controlsSettings.bShowTabs) { GetDlgItem(IDC_CHECK_HIDE_SINGLE_TAB).EnableWindow(); GetDlgItem(IDC_CHECK_TABS_ON_BOTTOM).EnableWindow(); diff --git a/Console/DlgSettingsStyles.h b/Console/DlgSettingsStyles.h index 2fe6ba1a..8b459db0 100644 --- a/Console/DlgSettingsStyles.h +++ b/Console/DlgSettingsStyles.h @@ -21,19 +21,19 @@ class DlgSettingsStyles DlgSettingsStyles(CComPtr& pOptionsRoot); BEGIN_DDX_MAP(DlgSettingsStyles) - DDX_CHECK(IDC_CHECK_SHOW_MENU, m_nShowMenu) - DDX_CHECK(IDC_CHECK_SHOW_TOOLBAR, m_nShowToolbar) - DDX_CHECK(IDC_CHECK_SHOW_STATUS, m_nShowStatusbar) - DDX_CHECK(IDC_CHECK_SHOW_TABS, m_nShowTabs) - DDX_CHECK(IDC_CHECK_HIDE_SINGLE_TAB, m_nHideSingleTab) - DDX_CHECK(IDC_CHECK_TABS_ON_BOTTOM, m_nTabsOnBottom) - DDX_CHECK(IDC_CHECK_SHOW_SCROLLBARS, m_nShowScrollbars) - DDX_CHECK(IDC_CHECK_FLAT_SCROLLBARS, m_nFlatScrollbars) - DDX_CHECK(IDC_CHECK_STYLE_CAPTION, m_nShowCaption) - DDX_CHECK(IDC_CHECK_STYLE_RESIZABLE, m_nResizable) - DDX_CHECK(IDC_CHECK_STYLE_BORDER, m_nBorder) - DDX_CHECK(IDC_CHECK_STYLE_TASKBAR, m_nTaskbarButton) - DDX_CHECK(IDC_CHECK_STYLE_TRAY, m_nTrayIcon) + DDX_CHECK(IDC_CHECK_SHOW_MENU, m_controlsSettings.bShowMenu) + DDX_CHECK(IDC_CHECK_SHOW_TOOLBAR, m_controlsSettings.bShowToolbar) + DDX_CHECK(IDC_CHECK_SHOW_STATUS, m_controlsSettings.bShowStatusbar) + DDX_CHECK(IDC_CHECK_SHOW_TABS, m_controlsSettings.bShowTabs) + DDX_CHECK(IDC_CHECK_HIDE_SINGLE_TAB, m_controlsSettings.bHideSingleTab) + DDX_CHECK(IDC_CHECK_TABS_ON_BOTTOM, m_controlsSettings.bTabsOnBottom) + DDX_CHECK(IDC_CHECK_SHOW_SCROLLBARS, m_controlsSettings.bShowScrollbars) + DDX_CHECK(IDC_CHECK_FLAT_SCROLLBARS, m_controlsSettings.bFlatScrollbars) + DDX_CHECK(IDC_CHECK_STYLE_CAPTION, m_stylesSettings.bCaption) + DDX_CHECK(IDC_CHECK_STYLE_RESIZABLE, m_stylesSettings.bResizable) + DDX_CHECK(IDC_CHECK_STYLE_BORDER, m_stylesSettings.bBorder) + DDX_CHECK(IDC_CHECK_STYLE_TASKBAR, m_stylesSettings.bTaskbarButton) + DDX_CHECK(IDC_CHECK_STYLE_TRAY, m_stylesSettings.bTrayIcon) DDX_CHECK(IDC_CHECK_STYLE_QUAKE, m_nQuake) DDX_UINT(IDC_INSIDE_BORDER, m_stylesSettings.dwInsideBorder) DDX_RADIO(IDC_TRANSPARENCY_TYPE, reinterpret_cast(m_transparencySettings.transType)) @@ -84,22 +84,7 @@ class DlgSettingsStyles CTrackBarCtrl m_sliderActiveAlpha; CTrackBarCtrl m_sliderInactiveAlpha; - int m_nShowMenu; - int m_nShowToolbar; - int m_nShowStatusbar; - int m_nShowTabs; - int m_nHideSingleTab; - int m_nTabsOnBottom; - int m_nShowScrollbars; - int m_nFlatScrollbars; - - int m_nShowCaption; - int m_nResizable; - int m_nTaskbarButton; - int m_nBorder; - int m_nTrayIcon; int m_nQuake; - int m_nTransparencyType; }; diff --git a/Console/PageSettingsTabs1.cpp b/Console/PageSettingsTabs1.cpp index c51d989f..1c44fe0c 100644 --- a/Console/PageSettingsTabs1.cpp +++ b/Console/PageSettingsTabs1.cpp @@ -18,7 +18,7 @@ PageSettingsTabs1::PageSettingsTabs1() : m_tabData() , m_strTitle(L"") , m_strIcon(L"") -, m_nUseDefaultIcon(0) +, m_bUseDefaultIcon(false) , m_strShell(L"") , m_strInitialDir(L"") , m_bRunAsUser(false) @@ -221,7 +221,7 @@ void PageSettingsTabs1::EnableControls() { BOOL bEnableEditIconCtrls = TRUE; - if (m_nUseDefaultIcon > 0) bEnableEditIconCtrls = FALSE; + if (m_bUseDefaultIcon) bEnableEditIconCtrls = FALSE; GetDlgItem(IDC_TAB_ICON).EnableWindow(bEnableEditIconCtrls); GetDlgItem(IDC_BTN_BROWSE_ICON).EnableWindow(bEnableEditIconCtrls); @@ -240,7 +240,7 @@ void PageSettingsTabs1::Load(shared_ptr& tabData) m_strTitle = m_tabData->strTitle.c_str(); m_strIcon = m_tabData->strIcon.c_str(); - m_nUseDefaultIcon = m_tabData->bUseDefaultIcon ? 1 : 0; + m_bUseDefaultIcon = m_tabData->bUseDefaultIcon; m_strShell = m_tabData->strShell.c_str(); m_strInitialDir = m_tabData->strInitialDir.c_str(); @@ -267,7 +267,7 @@ void PageSettingsTabs1::Save() m_tabData->strTitle = m_strTitle; m_tabData->strIcon = m_strIcon; - m_tabData->bUseDefaultIcon = (m_nUseDefaultIcon > 0); + m_tabData->bUseDefaultIcon = m_bUseDefaultIcon; m_tabData->strShell = m_strShell; m_tabData->strInitialDir = m_strInitialDir; diff --git a/Console/PageSettingsTabs1.h b/Console/PageSettingsTabs1.h index b4ad6cd8..bef7644f 100644 --- a/Console/PageSettingsTabs1.h +++ b/Console/PageSettingsTabs1.h @@ -27,7 +27,7 @@ class PageSettingsTabs1 BEGIN_DDX_MAP(PageSettingsTabs1) DDX_TEXT(IDC_TAB_TITLE, m_strTitle) DDX_TEXT(IDC_TAB_ICON, m_strIcon) - DDX_CHECK(IDC_CHECK_DEFAULT_ICON, m_nUseDefaultIcon) + DDX_CHECK(IDC_CHECK_DEFAULT_ICON, m_bUseDefaultIcon) DDX_TEXT(IDC_TAB_SHELL, m_strShell) DDX_TEXT(IDC_TAB_INIT_DIR, m_strInitialDir) DDX_CHECK(IDC_CHECK_RUN_AS_USER, m_bRunAsUser) @@ -92,7 +92,7 @@ class PageSettingsTabs1 CString m_strTitle; CString m_strIcon; - int m_nUseDefaultIcon; + bool m_bUseDefaultIcon; CString m_strShell; CString m_strInitialDir; diff --git a/Console/PageSettingsTabs2.cpp b/Console/PageSettingsTabs2.cpp index 5c366cd8..d6250885 100644 --- a/Console/PageSettingsTabs2.cpp +++ b/Console/PageSettingsTabs2.cpp @@ -17,8 +17,8 @@ PageSettingsTabs2::PageSettingsTabs2() : m_tabData() , m_nBkType(0) , m_strBkImage(L"") -, m_nRelative(0) -, m_nExtend(0) +, m_bRelative(false) +, m_bExtend(false) { } @@ -260,8 +260,8 @@ void PageSettingsTabs2::Load(shared_ptr& tabData) m_nBkType = static_cast(m_tabData->backgroundImageType); m_strBkImage = m_tabData->imageData.strFilename.c_str(); - m_nRelative = m_tabData->imageData.bRelative ? 1 : 0; - m_nExtend = m_tabData->imageData.bExtend ? 1 : 0; + m_bRelative = m_tabData->imageData.bRelative; + m_bExtend = m_tabData->imageData.bExtend; m_comboBkPosition.SetCurSel(static_cast(m_tabData->imageData.imagePosition)); @@ -286,15 +286,9 @@ void PageSettingsTabs2::Save() DoDataExchange(DDX_SAVE); m_tabData->backgroundImageType = static_cast(m_nBkType); - - if (m_tabData->backgroundImageType != bktypeNone) - { - m_tabData->crBackgroundColor = RGB(0, 0, 0); - } - - m_tabData->imageData.strFilename = m_strBkImage; - m_tabData->imageData.bRelative = m_nRelative > 0; - m_tabData->imageData.bExtend = m_nExtend > 0; + m_tabData->imageData.strFilename = m_strBkImage; + m_tabData->imageData.bRelative = m_bRelative; + m_tabData->imageData.bExtend = m_bExtend; m_tabData->imageData.imagePosition = static_cast(m_comboBkPosition.GetCurSel()); m_tabData->imageData.byTintOpacity = static_cast(m_sliderTintOpacity.GetPos()); diff --git a/Console/PageSettingsTabs2.h b/Console/PageSettingsTabs2.h index c469df1a..2d94ab8c 100644 --- a/Console/PageSettingsTabs2.h +++ b/Console/PageSettingsTabs2.h @@ -24,8 +24,8 @@ class PageSettingsTabs2 BEGIN_DDX_MAP(PageSettingsTabs2) DDX_RADIO(IDC_RADIO_BK_TYPE, m_nBkType) DDX_TEXT(IDC_BK_IMAGE, m_strBkImage) - DDX_CHECK(IDC_CHECK_BK_RELATIVE, m_nRelative) - DDX_CHECK(IDC_CHECK_BK_EXTEND, m_nExtend) + DDX_CHECK(IDC_CHECK_BK_RELATIVE, m_bRelative) + DDX_CHECK(IDC_CHECK_BK_EXTEND, m_bExtend) END_DDX_MAP() BEGIN_MSG_MAP(PageSettingsTabs2) @@ -76,8 +76,8 @@ class PageSettingsTabs2 int m_nBkType; CString m_strBkImage; - int m_nRelative; - int m_nExtend; + bool m_bRelative; + bool m_bExtend; }; ////////////////////////////////////////////////////////////////////////////// From cb5ccac5c4d7d2a96fc0f822f3e0f7d88f0ea98b Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 24 Jul 2011 21:50:49 -0400 Subject: [PATCH 109/207] Prevent pasting by mouse if pasting by menu is disabled --- Console/ConsoleView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index efb862b2..931889b6 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -1284,7 +1284,7 @@ void ConsoleView::ClearSelection() void ConsoleView::Paste() { - if (!::IsClipboardFormatAvailable(CF_UNICODETEXT)) return; + if (!CanPaste()) return; ::SendMessage(m_consoleHandler.GetConsoleParams()->hwndConsoleWindow, WM_SYSCOMMAND, SC_CONSOLE_PASTE, 0); } From 135cb984c0b6ed371dc56afd57f8afd6ed49462b Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 24 Jul 2011 22:09:51 -0400 Subject: [PATCH 110/207] Allow double-click to select a word (text between two spaces) --- Console/ConsoleView.cpp | 16 ++++++++++- Console/SelectionHandler.cpp | 56 ++++++++++++++++++++++++++++++++++++ Console/SelectionHandler.h | 1 + 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index 931889b6..a09d3b73 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -488,7 +488,21 @@ LRESULT ConsoleView::OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL m_mouseCommand = MouseSettings::cmdSelect; return 0; } - + + if (MouseSettings::clickDouble == mouseAction.clickType) + { + mouseAction.clickType = MouseSettings::clickSingle; + if ((*it)->action == mouseAction) + { + m_mouseCommand = MouseSettings::cmdSelect; + + MutexLock bufferLock(m_bufferMutex); + m_selectionHandler->SelectWord(GetConsoleCoord(point), m_appearanceSettings.stylesSettings.crSelectionColor, m_screenBuffer); + } + + mouseAction.clickType = MouseSettings::clickDouble; + } + // paste command it = mouseSettings.commands.get().find(MouseSettings::cmdPaste); if ((*it)->action == mouseAction) diff --git a/Console/SelectionHandler.cpp b/Console/SelectionHandler.cpp index 5c7cb3b5..eae501b2 100644 --- a/Console/SelectionHandler.cpp +++ b/Console/SelectionHandler.cpp @@ -64,6 +64,62 @@ SelectionHandler::~SelectionHandler() ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// +void SelectionHandler::SelectWord(const COORD& coordInit, COLORREF crSelectionColor, shared_array screenBuffer) +{ + if (m_selectionState > selstateNoSelection) return; + + // stop console scrolling while selecting + m_consoleHandler.StopScrolling(); + + if (!m_paintBrush.IsNull()) m_paintBrush.DeleteObject(); + m_paintBrush.CreateSolidBrush(crSelectionColor); + + m_consoleView.SetCapture(); + + m_coordInitial = coordInit; + + m_coordCurrent.X = m_coordInitial.X; + m_coordCurrent.Y = m_coordInitial.Y; + + SMALL_RECT& srWindow = m_consoleInfo->csbi.srWindow; + + int nDeltaX = m_coordCurrent.X - srWindow.Left; + int nDeltaY = m_coordCurrent.Y - srWindow.Top; + + if (nDeltaX < 0) nDeltaX = 0; + if (nDeltaY < 0) nDeltaY = 0; + + int nStartSel = nDeltaY * m_consoleParams->dwColumns + nDeltaX - 1; + while(nStartSel >= 0) + { + if (screenBuffer[nStartSel].charInfo.Char.AsciiChar == ' ') + break; + + --nStartSel; + } + + ++nStartSel; + m_coordInitial.X = short(nStartSel % m_consoleParams->dwColumns + srWindow.Left); + m_coordInitial.Y = short(nStartSel / m_consoleParams->dwColumns + srWindow.Top); + + DWORD nEndSel = nDeltaY * m_consoleParams->dwColumns + nDeltaX; + while (nEndSel < m_consoleParams->dwColumns * m_consoleParams->dwRows) + { + if (screenBuffer[nEndSel].charInfo.Char.AsciiChar == ' ') + break; + + ++nEndSel; + } + + // --nEndSel; + m_coordCurrent.X = short(nEndSel % m_consoleParams->dwColumns + srWindow.Left); + m_coordCurrent.Y = short(nEndSel / m_consoleParams->dwColumns + srWindow.Top); + + // pretend we're dragging the mouse, otherwise single-char selection is disallowed + m_selectionState = selstateSelecting; + + UpdateSelection(); +} ////////////////////////////////////////////////////////////////////////////// diff --git a/Console/SelectionHandler.h b/Console/SelectionHandler.h index b57cb868..f109ad7d 100644 --- a/Console/SelectionHandler.h +++ b/Console/SelectionHandler.h @@ -41,6 +41,7 @@ class SelectionHandler public: void StartSelection(const COORD& coordInit, COLORREF crSelectionColor, shared_array screenBuffer); + void SelectWord(const COORD& coordInit, COLORREF crSelectionColor, shared_array screenBuffer); void UpdateSelection(const COORD& coordCurrent, shared_array screenBuffer); void UpdateSelection(); bool CopySelection(const COORD& coordCurrent); From 45abb6a66e6997aa4d821f1f5eb23aa52a2014f5 Mon Sep 17 00:00:00 2001 From: Kirill Date: Tue, 20 Sep 2011 02:20:30 +0100 Subject: [PATCH 111/207] Add configuration setting to allow cmd-style copy/clear selection click When the option is disabled Copy/Clear selection mouse command will be executed independent from the clicked point, in oppose to the default behaviour when that command will copy if clicked inside the selection and just clear when clicked outside the selection. --- Console/Console.rc | 34 ++++++++++++++++++---------------- Console/ConsoleView.cpp | 5 +++++ Console/DlgSettingsBehavior.h | 1 + Console/SettingsHandler.cpp | 3 +++ Console/SettingsHandler.h | 1 + Console/resource.h | 1 + 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/Console/Console.rc b/Console/Console.rc index 1b6df638..d7fc389b 100644 --- a/Console/Console.rc +++ b/Console/Console.rc @@ -388,22 +388,24 @@ BEGIN CONTROL "Clear selection on copy",IDC_CHECK_CLEAR_ON_COPY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,30,90,10 CONTROL "Don't wrap long lines",IDC_CHECK_NO_WRAP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,108,15,82,10 CONTROL "Trim trailing spaces",IDC_CHECK_TRIM_SPACES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,107,30,77,10 - GROUPBOX "Copy && Paste",IDC_STATIC,0,0,216,50 - CONTROL "Windows (CR+LF)",IDC_RADIO_COPY_NEWLINE_CHAR,"Button",BS_AUTORADIOBUTTON | WS_GROUP,10,69,74,10 - CONTROL "Unix (LF)",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,10,83,45,10 - GROUPBOX "Copy newline character",IDC_STATIC,0,55,105,50,WS_GROUP - CONTROL "Scroll one screen",IDC_PAGE_SCROLL,"Button",BS_AUTORADIOBUTTON | WS_GROUP,121,70,70,10 - CONTROL "Scroll",IDC_PAGE_SCROLL2,"Button",BS_AUTORADIOBUTTON,121,85,29,10 - EDITTEXT IDC_SCROLL_PAGE_ROWS,153,83,33,14,ES_AUTOHSCROLL | ES_NUMBER | WS_GROUP - CONTROL "",IDC_SPIN_SCROLL_PAGE_ROWS,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,187,69,11,14 - LTEXT "rows",IDC_STATIC_ROWS,189,86,16,8 - GROUPBOX "Page Scrolling",IDC_STATIC,110,55,106,50 - CONTROL "Flash inactive tabs",IDC_CHECK_FLASH_TAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,124,75,10 - LTEXT "Flashes:",IDC_STATIC,19,141,28,8 - EDITTEXT IDC_TAB_FLASHES,48,138,33,14,ES_AUTOHSCROLL | ES_NUMBER | WS_GROUP - CONTROL "",IDC_SPIN_TAB_FLASHES,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,75,134,11,14 - CONTROL "Leave highlighted",IDC_CHECK_LEAVE_HIGHLIGHTED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,155,72,10 - GROUPBOX "Inactive tab activity flash",IDC_STATIC,0,110,105,66,WS_GROUP + GROUPBOX "Copy && Paste",IDC_STATIC,0,0,216,63 + CONTROL "Windows (CR+LF)",IDC_RADIO_COPY_NEWLINE_CHAR,"Button",BS_AUTORADIOBUTTON | WS_GROUP,10,82,74,10 + CONTROL "Unix (LF)",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,10,96,45,10 + GROUPBOX "Copy newline character",IDC_STATIC,0,68,105,50,WS_GROUP + CONTROL "Scroll one screen",IDC_PAGE_SCROLL,"Button",BS_AUTORADIOBUTTON | WS_GROUP,121,83,70,10 + CONTROL "Scroll",IDC_PAGE_SCROLL2,"Button",BS_AUTORADIOBUTTON,121,98,29,10 + EDITTEXT IDC_SCROLL_PAGE_ROWS,153,96,33,14,ES_AUTOHSCROLL | ES_NUMBER | WS_GROUP + CONTROL "",IDC_SPIN_SCROLL_PAGE_ROWS,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,187,82,11,14 + LTEXT "rows",IDC_STATIC_ROWS,189,99,16,8 + GROUPBOX "Page Scrolling",IDC_STATIC,110,68,106,50 + CONTROL "Flash inactive tabs",IDC_CHECK_FLASH_TAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,137,75,10 + LTEXT "Flashes:",IDC_STATIC,19,154,28,8 + EDITTEXT IDC_TAB_FLASHES,48,151,33,14,ES_AUTOHSCROLL | ES_NUMBER | WS_GROUP + CONTROL "",IDC_SPIN_TAB_FLASHES,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,75,147,11,14 + CONTROL "Leave highlighted",IDC_CHECK_LEAVE_HIGHLIGHTED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,168,72,10 + GROUPBOX "Inactive tab activity flash",IDC_STATIC,0,123,105,66,WS_GROUP + CONTROL "Position-sensitive copy",IDC_CHECK_SENSITIVE_COPY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,45,89,10 END IDD_SETTINGS_TABS_1 DIALOGEX 0, 0, 223, 171 diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index a09d3b73..cd62d531 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -1259,6 +1259,11 @@ void ConsoleView::Copy(const CPoint* pPoint /* = NULL */) bool bCopied = false; + if (!g_settingsHandler->GetBehaviorSettings().copyPasteSettings.bSensitiveCopy) + { + pPoint = 0; + } + if (pPoint != NULL) { bCopied = m_selectionHandler->CopySelection(GetConsoleCoord(*pPoint)); diff --git a/Console/DlgSettingsBehavior.h b/Console/DlgSettingsBehavior.h index 8adaacf8..e164fc42 100644 --- a/Console/DlgSettingsBehavior.h +++ b/Console/DlgSettingsBehavior.h @@ -23,6 +23,7 @@ class DlgSettingsBehavior BEGIN_DDX_MAP(DlgSettingsBehavior) DDX_CHECK(IDC_CHECK_COPY_ON_SELECT, m_behaviorSettings.copyPasteSettings.bCopyOnSelect) DDX_CHECK(IDC_CHECK_CLEAR_ON_COPY, m_behaviorSettings.copyPasteSettings.bClearOnCopy) + DDX_CHECK(IDC_CHECK_SENSITIVE_COPY, m_behaviorSettings.copyPasteSettings.bSensitiveCopy) DDX_CHECK(IDC_CHECK_NO_WRAP, m_behaviorSettings.copyPasteSettings.bNoWrap) DDX_CHECK(IDC_CHECK_TRIM_SPACES, m_behaviorSettings.copyPasteSettings.bTrimSpaces) DDX_RADIO(IDC_RADIO_COPY_NEWLINE_CHAR, m_nCopyNewlineChar) diff --git a/Console/SettingsHandler.cpp b/Console/SettingsHandler.cpp index 9a659a71..ca26248f 100644 --- a/Console/SettingsHandler.cpp +++ b/Console/SettingsHandler.cpp @@ -790,6 +790,7 @@ bool CopyPasteSettings::Load(const CComPtr& pSettingsRoot) XmlHelper::GetAttribute(pCopyPasteElement, CComBSTR(L"copy_on_select"), bCopyOnSelect, false); XmlHelper::GetAttribute(pCopyPasteElement, CComBSTR(L"clear_on_copy"), bClearOnCopy, true); + XmlHelper::GetAttribute(pCopyPasteElement, CComBSTR(L"sensitive_copy"), bSensitiveCopy, true); XmlHelper::GetAttribute(pCopyPasteElement, CComBSTR(L"no_wrap"), bNoWrap, false); XmlHelper::GetAttribute(pCopyPasteElement, CComBSTR(L"trim_spaces"), bTrimSpaces, false); XmlHelper::GetAttribute(pCopyPasteElement, CComBSTR(L"copy_newline_char"), nNewlineChar, 0); @@ -812,6 +813,7 @@ bool CopyPasteSettings::Save(const CComPtr& pSettingsRoot) XmlHelper::SetAttribute(pCopyPasteElement, CComBSTR(L"copy_on_select"), bCopyOnSelect); XmlHelper::SetAttribute(pCopyPasteElement, CComBSTR(L"clear_on_copy"), bClearOnCopy); + XmlHelper::SetAttribute(pCopyPasteElement, CComBSTR(L"sensitive_copy"), bSensitiveCopy); XmlHelper::SetAttribute(pCopyPasteElement, CComBSTR(L"no_wrap"), bNoWrap); XmlHelper::SetAttribute(pCopyPasteElement, CComBSTR(L"trim_spaces"), bTrimSpaces); XmlHelper::SetAttribute(pCopyPasteElement, CComBSTR(L"copy_newline_char"), static_cast(copyNewlineChar)); @@ -828,6 +830,7 @@ CopyPasteSettings& CopyPasteSettings::operator=(const CopyPasteSettings& other) { bCopyOnSelect = other.bCopyOnSelect; bClearOnCopy = other.bClearOnCopy; + bSensitiveCopy = other.bSensitiveCopy; bNoWrap = other.bNoWrap; bTrimSpaces = other.bTrimSpaces; copyNewlineChar = other.copyNewlineChar; diff --git a/Console/SettingsHandler.h b/Console/SettingsHandler.h index 072fccc6..ec040861 100644 --- a/Console/SettingsHandler.h +++ b/Console/SettingsHandler.h @@ -288,6 +288,7 @@ struct CopyPasteSettings : public SettingsBase bool bCopyOnSelect; bool bClearOnCopy; + bool bSensitiveCopy; bool bNoWrap; bool bTrimSpaces; diff --git a/Console/resource.h b/Console/resource.h index 042dd99f..a777b60a 100644 --- a/Console/resource.h +++ b/Console/resource.h @@ -190,6 +190,7 @@ #define IDC_CHECK_CLEAR_ON_COPY 1146 #define IDC_CHECK_INVERSE_SHIFT 1147 #define IDC_CHECK_USE_CONSOLE_TITLE 1147 +#define IDC_CHECK_SENSITIVE_COPY 1147 #define IDC_CHECK_TRIM_TAB_TITLES 1148 #define IDC_STATIC_TRIM_CHARS 1149 #define IDC_PAGE_SCROLL 1150 From 90eefceb4ba1e1057be5705ef8e6a846ac3670ac Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 25 Jul 2011 22:16:47 -0400 Subject: [PATCH 112/207] Attempt to avoid funny selection with a "slow double-click" The problem seems to exist due to an UpdateSelection(point), called from UpdateConsoleView, and/or due to a slight mouse move between two clicks of a double click, causing UpdateSelection(point) to change m_coordCurrent. It looks like we can trick SelectionHandler and ConsoleView to behave if we set the state above selstateSelecting. However selstateSelected is used to protect from accidental "second copy", hence it can't be used. --- Console/ConsoleView.cpp | 3 ++- Console/SelectionHandler.cpp | 3 +-- Console/SelectionHandler.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Console/ConsoleView.cpp b/Console/ConsoleView.cpp index cd62d531..03967938 100644 --- a/Console/ConsoleView.cpp +++ b/Console/ConsoleView.cpp @@ -553,7 +553,8 @@ LRESULT ConsoleView::OnMouseButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL m_mainFrame.SetSelectionSize(0); m_selectionHandler->ClearSelection(); } - else if (m_selectionHandler->GetState() == SelectionHandler::selstateSelecting) + else if (m_selectionHandler->GetState() == SelectionHandler::selstateSelecting || + m_selectionHandler->GetState() == SelectionHandler::selstateSelectWord) { m_selectionHandler->EndSelection(); m_mainFrame.SetSelectionSize(0); diff --git a/Console/SelectionHandler.cpp b/Console/SelectionHandler.cpp index eae501b2..becf6b21 100644 --- a/Console/SelectionHandler.cpp +++ b/Console/SelectionHandler.cpp @@ -115,8 +115,7 @@ void SelectionHandler::SelectWord(const COORD& coordInit, COLORREF crSelectionCo m_coordCurrent.X = short(nEndSel % m_consoleParams->dwColumns + srWindow.Left); m_coordCurrent.Y = short(nEndSel / m_consoleParams->dwColumns + srWindow.Top); - // pretend we're dragging the mouse, otherwise single-char selection is disallowed - m_selectionState = selstateSelecting; + m_selectionState = selstateSelectWord; UpdateSelection(); } diff --git a/Console/SelectionHandler.h b/Console/SelectionHandler.h index f109ad7d..5c8db549 100644 --- a/Console/SelectionHandler.h +++ b/Console/SelectionHandler.h @@ -19,7 +19,8 @@ class SelectionHandler selstateNoSelection = 0x00, selstateStartedSelecting= 0x01, selstateSelecting = 0x02, - selstateSelected = 0x03 + selstateSelected = 0x03, + selstateSelectWord = 0x04, }; public: From 5c741d9504d4002f43c6362b5b5635e7fd14b87a Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 17 Apr 2011 21:34:06 +0100 Subject: [PATCH 113/207] Add building CHM from HHP in Win32 Release build The complexity of the command line comes from the fact that hhc exits with code 1 when it *succeeds*. --- Console/Console.vcproj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Console/Console.vcproj b/Console/Console.vcproj index 2bdab2cf..609ccedd 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -897,6 +897,16 @@ + + + Date: Thu, 8 Sep 2011 01:13:52 +0100 Subject: [PATCH 114/207] Updates to the original Console help by Vivian De Smedt, Sergey Kozlov This is a cherry-pick of 5fed8695 with minor corrections. --- Console/Console.vcproj | 4 +++ help/console.hhc | 4 +++ help/console.hhp | 1 + help/html/copyright.html | 4 +-- help/html/menus.html | 12 +++++++ help/html/settings.html | 29 ++++++++++++++++ help/html/settings_appearance.html | 21 +++++++++--- help/html/settings_appearance_more.html | 24 +++++++++++++ help/html/settings_behavior.html | 42 +++++++++++++++++++++++ help/html/settings_tabs.html | 6 ++++ help/images/settings.png | Bin 0 -> 33149 bytes help/images/settings_appearance.png | Bin 11537 -> 12652 bytes help/images/settings_appearance_more.png | Bin 7718 -> 10662 bytes help/images/settings_behavior.png | Bin 4311 -> 12138 bytes help/images/settings_console.png | Bin 7477 -> 8602 bytes help/images/settings_hotkeys.png | Bin 8875 -> 9671 bytes help/images/settings_mouse.png | Bin 6672 -> 7966 bytes help/images/settings_tabs_background.png | Bin 16018 -> 8700 bytes help/images/settings_tabs_main.png | Bin 15408 -> 9273 bytes 19 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 help/html/settings.html create mode 100644 help/images/settings.png diff --git a/Console/Console.vcproj b/Console/Console.vcproj index 609ccedd..b6d1002d 100644 --- a/Console/Console.vcproj +++ b/Console/Console.vcproj @@ -951,6 +951,10 @@ RelativePath="..\help\html\running.html" > + + diff --git a/help/console.hhc b/help/console.hhc index 80f2d6d5..416096f8 100644 --- a/help/console.hhc +++ b/help/console.hhc @@ -40,6 +40,10 @@
    -
  • - - - -
      -
    • - - - -
  • diff --git a/help/console.hhp b/help/console.hhp index 5b355637..adb5efae 100644 --- a/help/console.hhp +++ b/help/console.hhp @@ -31,8 +31,6 @@ html\settings_mouse.html html\settings_tabs.html html\language.html html\tips_tricks.html -html\bugs_limitations.html -html\reporting_problems.html html\changelog.html html\credentials.html diff --git a/help/html/bugs_limitations.html b/help/html/bugs_limitations.html deleted file mode 100644 index 3ddbcde2..00000000 --- a/help/html/bugs_limitations.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Known bugs & limitations - - - - - -

    Known bugs & limitations

    - -

    - These are things that do not work (yet :-) -

    -